我知道可以在Python中跨模块共享全局变量。但是,我想知道这可能的程度和原因。例如,
global_mod.py
x = None
mid_access_mod.py
from global_mod import *
class delta:
def __init__(self):
print x
bot_modif_mod.py
import mid_access_mod
import global_mod
class mew:
def __init__(self):
global_mod.x = 5
def main():
m = mew()
d = mid_access_mod.delta()
即使所有模块共享全局变量x,也会打印无。为什么会这样?似乎x在mid_access_mod.py中被评估,然后由mew()在bot_modif_mod.py中赋值。
答案 0 :(得分:38)
这是因为您使用的是不可变值(int和None),导入变量就像按值传递,而不是通过引用传递。
如果你使global_mod.x成为一个列表并操纵它的第一个元素,那么它将按你的预期工作。
执行from global_mod import x
后,您在模块中创建了一个名称x
,其值与x
中global_mod
的值相同。对于像函数和类这样的东西,这可以像你期望的那样工作,因为人们(通常)以后不会重新分配这些名称。
正如Alex指出的那样,如果您使用import global_mod
,然后使用global_mod.x
,则可以避免此问题。您在模块中定义的名称将为global_mod
,它始终引用您想要的模块,然后使用属性访问权限获取x
将获得x
的最新值。
答案 1 :(得分:26)
from whatever import *
不是在您的代码中使用的好习惯用语 - 如果有的话,它可以在交互式会话中用作保存某些输入的快捷方式。它基本上“快照”了当时模块中的所有名称 - 如果您重新绑定任何这些名称,快照将变得陈旧,随之而来的是所有类型的问题。而这只是你通过使用可怜的from ... import *
构造注册的无法解决的混乱的开始。
需要我的建议吗?忘记你曾经听说过现有的构造,永远不会再使用它。使用import global_mod as m
并始终使用其他符合条件的名称,例如m.x
- 合格的名称如此在Python中更加方便和强大,而不仅仅是裸名,它甚至都不好笑。 (as m
语句的import
部分是完全可选的,基本上是为了简洁目的而存在,或者有时是为了解决名称冲突的一些问题;如果你觉得它很方便,可以使用它,因为它有没有缺点,但如果你认为没必要的话,不要强迫甚至不要使用。)
答案 2 :(得分:0)
我修改了示例以使用x的列表,并按照最高回答中的建议列出了分配(x [0] = ..),并且print返回了相同的初始值(None)。这验证了“来自global_mod import *”是一个副本,无论是否可变。
根据评论“import global_mod”的建议,如果“print global_mod.x =然后在mid_access_mod中使用。
答案 3 :(得分:0)
正如Ned Batchelder所提到的,只有值是共享的,而不是实际的对象。如果您想通过引用共享对象,那么您可能正在查找Thread-Local Data
。
例如:
import threading
g = threading.local()
g.population = '7 Billion'
现在,每当您想要访问或更改变量g.population时,您将获得它的更新值,前提是它与您尝试访问它的线程相同。
阅读Python文档:https://docs.python.org/3/library/threading.html#thread-local-data
答案 4 :(得分:0)
要解决此问题,只需将from global_mod import *
更改为import global_mod
。
新的 mid_access_mod.py 将是:
import global_mod
class delta:
def __init__(self):
print global_mod.x
可以找到here的原因。
由于引用和名称绑定在Python中的工作方式,如果你想更新模块中的一些符号,比如foo.bar,从该模块外部更新,并让其他导入代码“看到”更改,你必须以某种方式导入foo。