简体   繁体   中英

global variable doesn't change?

it doesn't matter what the input is, the output is always 0, like the global variables NEVER change. please help me I'm going crazy because i don't see any reason for this to show only 0

x=0
y=0
import math
import operator


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():

    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]
        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")}

        directions[direction.replace(" ","")]

        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()

As my comment says, your dict initialization is actually running those functions and setting values as the return values ( NoneType ). Do something like this instead.

1.) Initiate your dict OUTSIDE your while loop because you dont need to reinitialize every time.

2.) change it so the value is a tuple of your parameters like:

directions = {"UP":(operator.add,"x"),
              "DOWN":(operator.sub,"x"),
              "RIGHT":(operator.add,"y"),
              "LEFT":(operator.sub,"y")}

note that the dict does not include steps because you are going to use that as a variable for every call.

3.) change your function call by using this line:

move(steps,directions[direction][0],directions[direction][1])

in place of your current dict init/dict call.

The problem with this is that if your command is NOT a valid command, it will cause errors so I would put everything in a Try block like:

try:
    move(steps,directions[direction][0],directions[direction][1])
except KeyError:
    print('Not a valid key, try again')
else:
    #here is where you put the math code you do to edit the globals

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()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM