(Python 3.6)
考虑一个包奇数,包含两个模块 foo 和 bar 。我希望奇数的客户对包中的所有内容使用单个导入,而不必知道在foo中定义了什么以及在bar中定义了什么。所以我用以下内容定义了 __ init __。py :
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.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.foo ,每个命名空间用不同的方式定义 baz 。
如何实现我想要的,一个全局变量,由奇数的客户访问为 odd.baz ?
(是的,我知道我不应该使用像这样的全局变量。我已经将我实际想要完成的合理目标提炼到这个愚蠢的例子中,其中 odd.baz 说明了潜在的问题。)
答案 0 :(得分:1)
Python有名字,而不是变量
如果您在odd.foo.baz
中导入odd.__init__
,则会创建一个新名称odd.__init__.baz
,指向同一个int
对象12
。
如果您将名称odd.foo.baz
更改为指向另一个int
,13
,则这对名称odd.__init__.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
相似,您可以使用werkzeug.local.LocalProxy
:
from werkzeug.local import LocalProxy
baz = LocalProxy(lambda: GLOBALS['baz'])
示例:
>>> 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'>