You are doing these things wrong:
- You're initializing your dictionary not with functions that can be called, but with the results of four function calls. What you really want to do is create a partial.
- You are initializing your dictionary inside your while loop.
Additionally, storing that information globally isn't really what you want to be doing, but rather storing it within the scope of the while loop.
Lets look at what your dictionary definition is doing:
directions = {"UP":move(steps,operator.add,"x"),
"DOWN":move(steps,operator.sub,"x"),
"RIGHT":move(steps,operator.add,"y"),
"LEFT":move(steps,operator.sub,"y")}
Each of these assignments calls move with the appropriate values, and sets them to the value. However, move()
returns None
because there is no return
statement set for those: the globals are updated inside the function. So after one while
loop, your directions
array looks like this:
{"UP": None, "DOWN": None, "RIGHT": None, "LEFT": None}
And your x
and y
global values have been incremented and decremented once each. You can prove this by replacing your move
function with the following:
def move(steps,op_func,z):
if z == "x":
global x
x = op_func(x, int(steps))
print("x is now {}".format(x))
else:
global y
y = op_func(y, int(steps))
print("y is now {}".format(y))
In the REPL this is what you see:
>>> y= 0
>>> x= 0
>>> steps = 1
>>> directions = {"UP":move(steps,operator.add,"x"),
>>> "DOWN":move(steps,operator.sub,"x"),
... "RIGHT":move(steps,operator.add,"y"),
... "LEFT":move(steps,operator.sub,"y")}
... x is now 1
x is now 0
y is now 1
y is now 0
However, partials can help:
>>> f = partial(move, op_func=operator.add, z="x")
>>> f(1)
>>> x is now 1
Using the above, you want do define your directions
map like so:
directions = {"UP":partial(move, op_func=operator.add, z="x"),
"DOWN":partial(move, op_func=operator.sub, z="x"),
"RIGHT":partial(move, op_func=operator.add, z="y"),
"LEFT":partial(move, op_func=operator.sub, z="y")}
What this does is replace each "key" in your dictionary with a "partial function". A partial function as some of it's parameters 'filled in', and later on you can call that function with only the remaining value. Formally:
partial(f(a, b, c), b, c) -> g(a)
Whenever you call g
, b
, and c
will be consistently defined for a function call to f
.
Now all you have to do is change this line:
directions[direction.replace(" ","")]
To this:
move_func = directions[direction.replace(" ","")]
move_func(steps)
Re-writing and cleaning up the program a bit yields:
import math
import operator
from functools import partial
# Always do imports first then global vars
x=0
y=0
def move(steps,op_func,z):
if z == "x":
global x
x = op_func(x, int(steps))
else:
global y
y = op_func(y, int(steps))
def main():
# We only need to define this once
directions = {"UP":partial(move, op_func=operator.add, z="x"),
"DOWN":partial(move, op_func=operator.sub, z="x"),
"RIGHT":partial(move, op_func=operator.add, z="y"),
"LEFT":partial(move, op_func=operator.sub, z="y")}
user_direct=raw_input("Enter the way that you want the plane to move and how many steps you want it to move\n")
while user_direct != " ":
steps=user_direct[-1]
direction=user_direct[:-1].replace(" ","")
move_func = directions[direction]
move_func(steps)
user_direct=raw_input("Enter the way that you want the plane to move and how many steps you want it to move\n")
global x
global y
distance=math.sqrt(x**2+y**2)
print distance
main()