python中全局变量的频率?

时间:2012-09-28 15:07:33

标签: python

Stack Overflow在python中有很多关于全局变量的问题,它似乎会给来自其他语言的人带来一些混乱。范围规则并不完全像许多来自其他背景的人所期望的那样。

与此同时,代码的目的不是在类级别上,而是在模块级别上。因此,当所有内容都不一定包含在类中时,在成员变量中可以找到的状态可以放在模块级变量中。

所以我的问题是2部分:

1)我是否应该避免使用全局变量(特别是在函数中设置它们并使用global关键字)?

2)如果#1为是,是否存在预期使用它们的常见模式?

我在一个有很多不同语言的地方工作,我想减轻混乱,并确保pythonistas不会在以后讨厌我。

感谢您提供任何建设性意见。

4 个答案:

答案 0 :(得分:7)

我强烈建议您阅读这篇名为Singletons and their Problems in Python的博文。这让我重新考虑使用全局变量。一些选择引用:

  

但要注意。仅仅因为你没有实现单例设计模式,并不意味着你避免了单例的核心问题。单身人士的核心问题是全球共享状态。单例只不过是一个美化的全局变量,在像Java这样的语言中,有很多原因可以解释为什么你想要使用像单例这样的东西。在Python中,我们为单身人士提供了不同的东西,它有一个非常无辜的名字,隐藏了血腥的细节:模块。

     

那是对的人:Python模块是单身人士。并且它与单身模式有着相同的问题,只是它有点糟糕。

以下是此类共享状态可能导致的问题的一个示例:

  

为了不谈论无关紧要的事情,让我们看一下标准库中的一个模块mimetypes模块。

     

看看:

inited = False

def init(files=None):
    global inited
    db = MimeTypes()
    ...
  

这是来自Python附带的mimetypes模块的实际代码,只是删除了更多的血腥细节。关键是,有共享状态。共享状态是一个布尔标志,如果模块初始化则为True,否则为False。现在这个特殊情况可能不是那么有问题(相信我,它是)因为mimetypes初始化自己,但你可以看到init函数有一个files参数。如果将文件列表传递给该函数,它将使用这些文件中的mime信息重新初始化内存中的mime数据库。现在想象如果你有两个库用两个不同的源初始化mimetypes会发生什么......

这是一个足够普遍的模式,我自己也做过了......但是例如更好的方法是:init返回实现所有方法的类的实例,以及其他方法部分代码可以init来获得具有不干扰前者的不同参数的不同实例。 “缺点”是你必须将这个实例传递给任何不想初始化新代码的代码,但是“缺点”的好处在于它使你的依赖关系显而易见。

无论如何,简而言之,我会尽量避免使用它,但是如果您对具有隐式单例的代码感到满意,那就去吧。

答案 1 :(得分:3)

简而言之,是的,您应该避免使用global关键字。它可能在语言中是有原因的,但我通常认为它是一种代码味道 - 如果你有一些你要跟上的状态,将它封装在一个类中。这比使用global要脆弱得多。

答案 2 :(得分:3)

我在你的另一个问题上发表了这个评论,所以这是我的2分:

Python是面向对象的,但您不必使用它。但是如果你选择,你可以利用Class的这种机制来保存一些属性:

class Config():
"""
hold some vars for example.
"""
def __init__(self):
    self.CONFIG_LOG_FILE_DIR='/tmp2/ozn/venus_mon_log/'
    self.DATE_FORMAT="%Y%m%d"
    #self.FILE_NAME_BASE_TEMPLATE=eval('datetime.datetime.now().strftime(self.DATE_FORMAT)')+'-venus_utilization.log'
    self.FILE_NAME_BASE_TEMPLATE='venus_utilization.log'
    self.FILE_NAME=self.CONFIG_LOG_FILE_DIR+self.FILE_NAME_BASE_TEMPLATE
    self.MAX_FILE_SIZE=1024*1024*50 # in Byte, 50 in MB.

您可以创建一个允许您访问属性的实例:

   cfg = Config()

然后使用以下方式访问它们:

   cfg.MAX_FILE_SIZE

甚至改变它们:

   cfg.MAX_FILE_SIZE=50000 
   cfg.MAX_FILE_SIZE=calculateNewSize() 

依旧...... 你也可以这样做:

 # this will print all items that an instance has    
 if options.debug:
    print "DEBUG INFO:"
    for k,v in vars(cfg).iteritems():
        print k,v

答案 3 :(得分:2)

Globals并不是真正的禁忌,只是你必须记住在使用它们之前将它们声明为函数的全局。在我看来,这实际上使它们更清晰,因为用户看到你明确使用全局。

我会更害怕非pythonistas不理解python全局变量,修改代码而不添加正确的全局声明。