开发者

Python global variable insanity

开发者 https://www.devze.com 2023-01-04 22:56 出处:网络
You have three files: main.py, second.py, and common.py common.py #!/usr/bin/python GLOBAL_ONE = \"Frank\"

You have three files: main.py, second.py, and common.py

common.py

#!/usr/bin/python
GLOBAL_ONE = "Frank"

main.py

#!/usr/bin/python
from common import *
from second import secondTest

if __name__ == "__main__":
    global GLOBAL_ONE
    print GLOBAL_ONE #Prints "Frank"
    GLOBAL_ONE = "Bob"
    print GLOBAL_ONE #Prints "Bob"

    secondTest()

    print GLOBAL_ONE #Prints "Bob"

second.py

#!/usr/bin/python
from common import *

def secondTest():
    global GLOBAL_ONE
    print GLOBAL_ONE #Prints "Frank"

Why does secondTest not use the global variables of its calling program?开发者_JAVA技巧 What is the point of calling something 'global' if, in fact, it is not!?

What am I missing in order to get secondTest (or any external function I call from main) to recognize and use the correct variables?


global means global for this module, not for whole program. When you do

from lala import *

you add all definitions of lala as locals to this module.

So in your case you get two copies of GLOBAL_ONE


The first and obvious question is why?

There are a few situations in which global variables are necessary/useful, but those are indeed few.

Your issue is with namespaces. When you import common into second.py, GLOBAL_ONE comes from that namespace. When you import secondTest it still references GLOBAL_ONE from common.py.

Your real issue, however, is with design. I can't think of a single logical good reason to implement a global variable this way. Global variables are a tricky business in Python because there's no such thing as a constant variable. However, convention is that when you want to keep something constant in Python you name it WITH_ALL_CAPS. Ergo:

somevar = MY_GLOBAL_VAR  # good!
MY_GLOBAL_VAR = somevar  # What? You "can't" assign to a constant! Bad!

There are plenty of reasons that doing something like this:

earth = 6e24
def badfunction():
    global earth
    earth += 1e5
print '%.2e' % earth

is terrible.

Of course if you're just doing this as an exercise in understanding namespaces and the global call, carry on.

If not, some of the reasons that global variables are A Bad Thing™ are:

  • Namespace pollution
  • Functional integration - you want your functions to be compartmentalized
  • Functional side effects - what happens when you write a function that modifies the global variable balance and either you or someone else is reusing your function and don't take that into account? If you were calculating account balance, all of the sudden you either have too much, or not enough. Bugs like this are difficult to find.

If you have a function that needs a value, you should pass it that value as a parameter, unless you have a really good reason otherwise. One reason would be having a global of PI - depending on your precision needs you may want it to be 3.14, or you may want it 3.14159265... but that is one case where a global makes sense. There are probably only a handful or two of real-world cases that can use globals properly. One of the cases are constants in game programming. It's easier to import pygame.locals and use KP_UP than remember the integer value responding to that event. These are exceptions to the rule.

And (at least in pygame) these constants are stored in a separate file - just for the constants. Any module that needs those constants will import said constants.

When you program, you write functions to break your problem up into manageable chunks. Preferably a function should do one thing, and have no side effects. That means a function such as calculatetime() should calculate the time. It probably shouldn't go reading a file that contains the time, and forbid that it should do something like write the time somewhere. It can return the time, and take parameters if it needs them - both of these are good, acceptable things for functions to do. Functions are a sort of contract between you (the programmer of the function) and anyone (including you) who uses the function. Accessing and changing global variables are a violation of that contract because the function can modify the outside data in ways that are not defined or expected. When I use that calculatetime() function, I expect that it will calculate the time and probably return it, not modify the global variable time which responds to the module time that I just imported.

Modifying global variables break the contract and the logical distinction between actions that your program takes. They can introduce bugs into your program. They make it hard to upgrade and modify functions. When you use globals as variables instead of constant, death awaits you with sharp pointy teeth!


Compare the results of the following to yours. When you use the correct namespaces you will get the results you expect.

common.py

#!/usr/bin/python
GLOBAL_ONE = "Frank"

main.py

#!/usr/bin/python
from second import secondTest
import common

if __name__ == "__main__":
    print common.GLOBAL_ONE # Prints "Frank"
    common.GLOBAL_ONE = "Bob"
    print common.GLOBAL_ONE # Prints "Bob"

    secondTest()

    print common.GLOBAL_ONE # Prints "Bob"

second.py

#!/usr/bin/python
import common

def secondTest():
    print common.GLOBAL_ONE # Prints "Bob"


Let me first say that I agree with everybody else who answered before saying that this is probably not what you want to do. But in case you are really sure this is the way to go you can do the following. Instead of defining GLOBAL_ONE as a string in common.py, define it as a list, that is, GLOBAL_ONE = ["Frank"]. Then, you read and modify GLOBAL_ONE[0] instead of GLOBAL_ONE and everything works the way you want. Note that I do not think that this is good style and there are probably better ways to achieve what you really want.

0

精彩评论

暂无评论...
验证码 换一张
取 消