Python名称空间和导入:在导入的模块中设置全局变量的值会创建第二个不相关的全局变量?
(Python 3.6) 考虑一个包含两个模块foo和bar的包odd。我希望奇数的客户对包中的所有内容使用单一导入,而不必知道foo和bar中定义了什么。因此,我定义了一个\uuuu init\uuuu.py,如下所示:Python名称空间和导入:在导入的模块中设置全局变量的值会创建第二个不相关的全局变量?,python,python-3.x,Python,Python 3.x,(Python 3.6) 考虑一个包含两个模块foo和bar的包odd。我希望奇数的客户对包中的所有内容使用单一导入,而不必知道foo和bar中定义了什么。因此,我定义了一个\uuuu init\uuuu.py,如下所示: from .foo import * from .bar import * foo.py包含一个全局变量baz和一个设置baz值的函数set_baz(),如下所示: baz = 12 def set_baz(): global baz print('Ba
from .foo import *
from .bar import *
foo.py包含一个全局变量baz和一个设置baz值的函数set_baz(),如下所示:
baz = 12
def set_baz():
global baz
print('Baz was {}'.format(baz))
baz = 13
print('Now it is changed to {}'.format(baz))
当我导入odd(从其他地方)并查看odd.baz的值时,我得到了我所期望的,原始值12
In [2]: import odd
In [3]: odd.baz
Out[3]: 12
但是当我运行set_baz()时,它不会像预期的那样更改odd.baz的值,而是更改一个不同的全局变量:odd.foo.baz
In [4]: odd.set_baz()
Baz was 12
Now it is changed to 13
In [5]: odd.baz
Out[5]: 12
In [6]: odd.foo.baz
Out[6]: 13
显然有两个不相关的名称空间,一个用于odd,另一个用于odd.foo,每个名称空间对baz的定义不同
我如何实现我想要的,单个全局变量,由odd asodd.baz的客户访问
(是的,我知道我不应该使用这样的全局变量。我已经用odd.baz将我实际上试图实现的合理目标提炼到这个愚蠢的例子中,它说明了根本的问题。)Python有名称,而不是变量。
如果在
odd.\uuuu init\uuuuu
中导入odd.foo.baz
,它将创建一个新名称odd.\uuuuu init\uuuuuuu.baz
指向相同的int
对象12
如果将名称
odd.foo.baz
更改为指向另一个int
,13
,则这对名称odd.\uuuu init\uuuuuuu.baz
没有任何影响
这种怪癖是为什么全球人被认为是坏习惯的原因之一(非常特殊的情况除外)
您可以通过将baz
封装到一个可变对象(如dict
)中来解决此问题:
odd.foo.py
:
GLOBALS = {'baz': 12}
def set_baz():
print('Baz was {}'.format(GLOBALS['baz']))
GLOBALS['baz'] = 13
print('Now it is changed to {}'.format(GLOBALS['baz']))
def get_baz():
return GLOBALS['baz']
要使名称baz
的行为类似于int
,可以使用:
例如:
>>> test.baz
12
>>> test.set_baz()
Baz was 12
Now it is changed to 13
>>> test.baz
13
>>> test.baz + 4
17
>>> test.baz.__class__
<class 'werkzeug.local.LocalProxy'>
>test.baz
12
>>>test.set_baz()
巴兹12岁
现在改为13
>>>test.baz
13
>>>test.baz+4
17
>>>测试。baz.\u类__
try nonlocal而不是globalIn short:“from.foo import*”不会将导入模块中的名称公开到导入模块中。而是“from.foo import*”在导入模块中创建新名称,新名称最初采用与导入模块中相应名称相同的值。现在我明白了。谢谢
>>> test.baz
12
>>> test.set_baz()
Baz was 12
Now it is changed to 13
>>> test.baz
13
>>> test.baz + 4
17
>>> test.baz.__class__
<class 'werkzeug.local.LocalProxy'>