Python全局变量精神错乱

时间:2010-06-25 15:29:56

标签: python

您有三个文件:main.py,second.py和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"

为什么secondTest不使用其调用程序的全局变量?如果事实上它不是“全球性”的话,有什么意义呢??

为了获得secondTest(或我从main调用的任何外部函数)识别和使用正确的变量,我缺少什么?

4 个答案:

答案 0 :(得分:11)

global表示此模块的全局,而非整个程序。当你这样做

from lala import *

您将lala的所有定义添加为 locals 到此模块

因此,在您的情况下,您将获得GLOBAL_ONE

的两份副本

答案 1 :(得分:5)

第一个显而易见的问题是为什么?

在某些情况下,全局变量是必要/有用的,但实际上很少。

您的问题在于命名空间。将common导入second.py时,GLOBAL_ONE来自该命名空间。导入secondTest时,它仍会引用common.py。{/ p>中的GLOBAL_ONE

然而,你真正的问题在于设计。我想不出以这种方式实现全局变量的单一逻辑良好原因。全局变量在Python中是一项棘手的业务,因为没有常量变量这样的东西。但是,惯例是当你想在Python中保持一些常量时,你可以命名为WITH_ALL_CAPS。埃尔戈:

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

有很多理由做这样的事情:

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

非常可怕。

当然,如果您只是将其作为理解名称空间和global调用的练习,请继续。

如果没有,全局变量是A Bad Thing™的一些原因是:

  • 命名空间污染
  • 功能集成 - 您希望将功能划分为
  • 功能性副作用 - 当您编写修改全局变量balance的函数并且您或其他人正在重用您的函数而不考虑该函数时会发生什么?如果你在计算账户余额,突然间你要么太多,要么不够。像这样的虫子很难找到。

如果你有一个需要值的函数,你应该将该值作为参数传递,除非你有一个非常好的理由。一个原因是拥有PI的全局 - 根据您的精度需求,您可能希望它为3.14,或者您可能需要它3.14159265 ...但这是一个全局有意义的情况。可能只有少数或两个真实案例可以正确使用全局变量。其中一个案例是游戏编程中的常量。导入pygame.locals并使用KP_UP比记住响应该事件的整数值更容易。这些是规则的例外

并且(至少在pygame中)这些常量存储在一个单独的文件中 - 仅用于常量。任何需要这些常量的模块都将导入所述常量。

编程时,编写函数将问题分解为可管理的块。优选地,函数应该一个事物,并且没有副作用。这意味着诸如 calculatetime()之类的函数应该计算时间。它可能不应该读取包含时间的文件,并且禁止它应该执行某些操作,例如 write 。它可以返回时间,并在需要时获取参数 - 这些都是函数要做的好的,可接受的事情。函数是您(函数的程序员)和使用该函数的任何人(包括您)之间的一种契约。访问和更改全局变量违反了该合同,因为该函数可以以未定义或预期的方式修改外部数据。当我使用calculatetime()函数时,我希望它会计算时间并可能返回它,而不是修改响应我刚刚导入的模块时间的全局变量时间。

修改全局变量会破坏合同以及程序所采取的操作之间的逻辑区别。他们可以在您的程序中引入错误。它们使升级和修改功能变得困难。当您使用全局变量作为变量而不是常量death awaits you with sharp pointy teeth!

答案 2 :(得分:2)

将以下结果与您的结果进行比较。当您使用正确的命名空间时,您将获得预期的结果。

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"

答案 3 :(得分:1)

首先我要说的是,我同意其他所有回答的人,然后才说这可能你想做什么。但如果您确定这是可行的方法,您可以执行以下操作。不要将GLOBAL_ONE定义为common.py中的字符串,而是将其定义为列表,即GLOBAL_ONE = ["Frank"]。然后,您阅读并修改GLOBAL_ONE[0]而不是GLOBAL_ONE,一切都按照您想要的方式进行。请注意,我认为这不是一种好的风格,并且可能有更好的方法来实现您真正想要的。