你是否在Python中使用"global"语句?

62

我正在阅读一个关于Python global语句的问题("Python作用域"),回想起我作为一个Python初学者时经常使用这个语句(我经常使用global),而现在几年过去了,我不再使用它。我甚至认为它有点不符合Python的风格。

你在Python中使用这个语句吗?随着时间的推移,你对它的使用方式是否改变了?

12个回答

59

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

_cached_result = None
def myComputationallyExpensiveFunction():
    global _cached_result
    if _cached_result:
       return _cached_result

    # ... figure out result

    _cached_result = result
    return result

我使用 'global' 是因为它对于函数的读者来说是有意义和清晰的。我也知道有这种模式,它等价于 'global',但会给读者带来更多的认知负担:

def myComputationallyExpensiveFunction():
    if myComputationallyExpensiveFunction.cache:
        return myComputationallyExpensiveFunction.cache

    # ... figure out result

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

15
我倾向于在这种情况下使用装饰器模块的'memoize'函数,但我不能否认你全局使用的清晰度 :) - Matthew Trevor
6
我之前不知道可以定义一个函数属性,例如myComputationallyExpensiveFunction.cache,并在函数内部使用它,谢谢! - Aurelio Martin Massoni
2
我以前从未听说过给函数分配属性,这太棒了!谢谢! - brad
5
第二个例子的第二行应该是 "if getattr(myComputationallyExpensiveFunction, "cache", None):",否则会出现 AttributeError。 - Andy Grover
@AndyGrover 我不需要这样做,代码没有问题,我也没有看到任何 AttributeError(?) - AJP

15

在我三年多的Python专业使用和五年的Python业余爱好者经验中,我从未在任何生产代码中有过这个语句的合法用途。我需要改变的任何状态都存储在类中,或者如果有一些“全局”状态,则存储在某个共享结构中,例如全局缓存。


1
曾经考虑首次使用全局变量,特别是用于创建全局缓存。您的回复似乎表明您正在使用其他方式来创建和维护全局缓存...您可以分享一下您是如何实现这一点的吗? - joeyagreco

10

我在函数创建或设置全局变量的情况下使用它。以下是一些示例:

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
...
或者
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

8
在我的看法中,一旦你在Python代码中感觉需要使用全局变量,就是停下来进行重构代码的好时机。
在代码中加入global并延迟重构过程可能听起来很有希望,如果你的截止日期临近的话,但相信我,除非你真的不得不这样做(比如你的代码因某些奇怪的原因停止工作,你必须进行调试,并遇到一些那些global变量导致事情混乱),否则你不会回去修复它们的。
所以,老实说,即使允许使用全局变量,我也尽可能避免使用它们。即使这意味着围绕你的代码片段建立一个简单的类。

3

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

我的主函数解析参数并将其传递给执行脚本工作的任何函数...但是将提供的选项写入全局 'opts' 字典。

Shell 脚本选项通常调整 'leaf' 行为,将 'opts' 字典通过每个参数列表进行线程处理不方便(也不必要)。


3

对象是具有非本地状态的首选方式,因此很少需要全局变量。我认为即将推出的nonlocal修饰符也不会被广泛使用,我认为它主要是为了让lispers停止抱怨 :-)


2
很少。我还没有找到任何用途。

我有一个VERBOSE常量变量,在命令行(argparsing)中设置。它需要传递给模块中的大多数函数。它是模块级别上的“只读”变量。声明为全局变量是否比将其传递给几乎每个仅需读取它进行日志记录的函数更好? - undefined

2

这在线程中共享状态时非常有用(需要使用锁机制)。

然而,我很少甚至从不使用它。


2

我曾在一些快速且简单的脚本中使用它,以自动化某些一次性任务。但如果是任何规模更大或需要重复使用的项目,我会寻找更加优雅的解决方案。


1

偶尔会出现这种情况。但是重构总是一个很好的起点。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接