你在Python中使用“全局”语句吗?

Do you use the “global” statement in Python?

我在读关于python global语句("python scope")的一个问题,我还记得在我还是一个python初学者的时候(我经常使用global)使用这个语句的频率,以及几年后,我是如何永远不使用它的。我甚至认为它有点"非Python式"。

在python中使用这个语句吗?你对它的使用是否随时间而改变?


我在这样的上下文中使用"global":

1
2
3
4
5
6
7
8
9
10
_cached_result = None
def myComputationallyExpensiveFunction():
    global _cached_result
    if _cached_result:
       return _cached_result

    # ... figure out result

    _cached_result = result
    return result

我使用"全局"是因为它是有意义的,并且对函数的读者来说是清楚的。我也知道有这样的模式,这是等效的,但给读者带来了更多的认知负担:

1
2
3
4
5
6
7
8
9
def myComputationallyExpensiveFunction():
    if myComputationallyExpensiveFunction.cache:
        return myComputationallyExpensiveFunction.cache

    # ... figure out result

    myComputationallyExpensiveFunction.cache = result
    return result
myComputationallyExpensiveFunction.cache = None


在我3年以上专业使用Python的过程中,我从未在任何生产代码中合法使用过该语句,作为一个Python爱好者,我也有5年多的时间。我需要更改的任何状态都存在于类中,或者,如果存在一些"全局"状态,它就位于一些共享结构中,如全局缓存。


我已经在函数创建或设置变量的情况下使用了它,这些变量将全局使用。以下是一些例子:

1
2
3
4
5
6
7
8
discretes = 0
def use_discretes():
    #this global statement is a message to the parser to refer
    #to the globally defined identifier"discretes"
    global discretes
    if using_real_hardware():
        discretes = 1
...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
file1.py:
    def setup():
        global DISP1, DISP2, DISP3
        DISP1 = grab_handle('display_1')
        DISP2 = grab_handle('display_2')
        DISP3 = grab_handle('display_3')
        ...

file2.py:
    import file1

    file1.setup()
    #file1.DISP1 DOES NOT EXIST until after setup() is called.
    file1.DISP1.resolution = 1024, 768

在我看来,一旦您觉得有必要在Python代码中使用全局变量,就应该停一下,重新构造代码了。把global放在代码中,如果死线很近,那么延迟重构过程可能听起来很有希望,但是,相信我,除非你真的不得不像你的代码由于某些奇怪的原因停止工作一样,你必须调试它,你会遇到一些global变量,以及所有这些变量。做就是把事情搞砸。

所以,老实说,即使是允许的,我也尽量避免使用它。即使它意味着围绕代码构建一个简单的类。


我将其用于带有命令行脚本和"optparse"的全局选项:

我的main()解析参数,并将其传递给执行脚本工作的任何函数…但将提供的选项写入全局"opts"字典。

shell脚本选项通常会调整"leaf"行为,并且不方便(也不必要)将"opts"字典贯穿到每个参数列表中。


对象是具有非本地状态的首选方式,因此很少需要全局。我不认为即将到来的非本地修改器也将被广泛使用,我认为它主要是为了让Lispers停止抱怨:—)


我在快速和肮脏的一次性脚本中使用它来自动执行某个一次性任务。任何比这更大的东西,或者需要重用的东西,我会找到一种更优雅的方式。


它可以在线程中用于共享状态(周围有锁定机制)。

然而,我很少使用它。


很少。我还没有找到它的用途。


我避免使用它,而且我们甚至有一个皮林特规则,在我们的生产代码中禁止使用它。我真的认为它根本不应该存在。


一次或两次。但重构始终是一个好的起点。


如果我能避免,不。据我所知,总有一种方法可以避免。但我也不是说这完全没用