在马克·卢茨的《学习Python》中混淆了global的用法

2024-06-06 21:54:21 发布

您现在位置:Python中文网/ 问答频道 /正文

在第5版的第551页上,有一个名为thismod.py的文件:

var = 99

def local():
    var = 0

def glob1():
    global var
    var+=1

def glob2():
    var = 0
    import thismod
    thismod.var+=1

def glob3():
    var = 0
    import sys
    glob = sys.modules['thismod']
    glob.var+=1

def test():
    print(var)
    local(); glob1(); glob2(); glob3()
    print(var)

之后,在终端中运行测试,如下所示:

>>> import thismod
>>> thismod.test()
99
102
>>> thismod.var
102

local()函数的使用非常有意义,因为python在local()函数的局部范围内生成变量var。然而,当涉及到全局变量的任何用法时,我就不知所措了

如果我做一个函数如下:

def nonglobal():
    var+=1

在终端中运行此函数时,出现UnboundLocalError。我目前的理解是,该函数将运行,首先搜索thismod.nonglobal的本地范围,然后在nonglobal()中找不到对var的赋值,然后搜索thismod.py文件的全局范围,其中它将找到值为99的thismod.var,但它没有。但是,在终端中紧接着运行thismod.var会产生预期的值。因此,我显然还不明白glob1()中的global var声明发生了什么

我原以为glob2()中的var = 0行也会发生上述情况,但这只作为局部变量(到glob2()?),尽管在赋值之前已经运行了glob1()的代码。我还以为glob2()中的import thismod行会将var重置为99,但这是另一件让我措手不及的事情;如果我把这行注释掉,下一行就失败了

简言之,尽管我读过这本书的这一章,但我还是不知道这里的全局范围/导入是怎么回事。我觉得我理解了关于全局和范围的讨论,但是这个例子告诉我我不理解。我感谢任何能帮助我解决这个问题的解释和/或进一步阅读

谢谢


Tags: 文件函数pyimport终端varlocaldef
1条回答
网友
1楼 · 发布于 2024-06-06 21:54:21

除非使用global关键字导入,否则全局范围中的变量只能在任何局部函数的只读容量中使用。尝试向它们写入将产生错误

使用赋值运算符=创建一个与全局变量同名的局部变量,将“隐藏”全局变量(即使全局变量不可访问,而有利于局部变量,它们之间没有其他连接)

算术赋值运算符(+=-=/=等)在这个范围内使用奇怪的规则。一方面是赋值给变量,但另一方面它们是可变的,全局变量是只读的。因此,除非首先使用global将全局变量引入局部范围,否则会出现错误

无可否认,python对此有奇怪的规则。一般来说,将全局变量用于只读目的是可以的(不必将它们作为global导入以使用它们的值),除非在函数中的任何点对该变量进行阴影处理,即使该点在将要使用其值的点之后。这可能与函数在执行def语句时如何定义自身有关:

var = 10

def a():
    var2 = var
    print(var2)

def b():        
    var2 = var  # raises an error on this line, not the next one
    var = var2 
    print(var)

a()  # no errors, prints 10 as expected
b()  # UnboundLocalError: local variable 'var' referenced before assignment

长话短说,您可以随意以只读的方式使用全局变量,而无需做任何特殊的操作。实际修改全局变量(通过重新分配;修改全局变量的属性很好),或者要以任何容量使用全局变量,同时也使用同名的局部变量,必须使用global关键字将它们引入


glob2()而言,名称thismod不在名称空间(即范围)中,直到您import将其放入名称空间中。因为thismod.var是现在局部变量的属性,而不是全局只读变量,所以我们可以很好地对它进行写入。只读限制实际上只适用于同一文件中的全局变量

glob3()的作用与glob2相同,只是它引用了sys的导入模块列表,而不是使用import关键字。这与import表现出的行为基本相同(尽管过于简单化了)-一般来说,模块只加载一次,再次尝试导入它们(从任何地方,例如在多个文件中)将得到第一次导入的相同实例importlib有办法解决这个问题,但这不是立即相关的

相关问题 更多 >