如何从另一个模块更改模块variables?

假设我有一个名为bar的包,它包含bar.py

 a = None def foobar(): print a 

__init__.py

 from bar import a, foobar 

然后我执行这个脚本:

 import bar print bar.a bar.a = 1 print bar.a bar.foobar() 

这是我所期望的:

 None 1 1 

这是我得到的:

 None 1 None 

任何人都可以解释我的误解?

你正在使用from bar import aa在导入模块的全局范围(或​​任何导入语句所在的范围)中成为一个符号。 所以当你给a赋一个新的值a ,你只需要改变一个值,而不是实际的值。 尝试直接使用__init__.py import bar导入bar.py ,然后通过设置bar.a = 1进行实验。 这样,你实际上正在修改bar.__dict__['a'] ,这是在这个上下文中'真正'的价值。

这有点复杂的三层,但bar.a = 1更改名为bar的模块中的值,实际上是从__init__.py派生的。 它不会改变foobar看到的值,因为foobar存在于实际的文件bar.py 。 如果你想改变,你可以设置bar.bar.a

这是使用import语句的from foo import barforms的危险之一:它将bar拆分为两个符号,一个从foo中全局可见,从foo开始指向原始值,另一个符号在import语句被执行。 改变符号点的位置也不会改变它指向的值。

当试图从交互式解释器reload模块时,这种东西是一个杀手。

这个问题的难点之一是你有一个名为bar/bar.py的程序: import bar导入bar/__init__.pybar/bar.py ,这取决于它在哪里完成,这使得它有点麻烦跟踪哪abar.a

下面是它的工作原理:

理解发生什么的关键是要认识到,在你的__init__.py

 from bar import a 

实际上做了类似的事情

 a = bar.a # … with bar = bar/bar.py (as if bar were imported locally from __init__.py) 

并定义一个新variables( bar/__init__.py:a ,如果你愿意的话)。 因此,您from bar import a __init__.py将名称bar/__init__.py:a到原始bar.py:a对象( None )。 这就是为什么你可以from bar import a as a2__init__.py中将from bar import a as a2 :在这种情况下,显然你有bar/bar.py:a和一个独特的variables名称bar/__init__.py:a2 (在你的情况下,两个variables的名称都是a ,但是它们仍然存在于不同的名称空间中:在__init__.py ,它们是bar.aa )。

现在,当你这样做

 import bar print bar.a 

你正在访问variablesbar/__init__.py:a (因为import bar导入你的bar/__init__.py )。 这是你修改的variables(1)。 你没有触及variablesbar/bar.py:a的内容bar/bar.py:a 。 所以当你以后做

 bar.foobar() 

你可以调用bar/bar.py:foobar() ,它从bar/bar.py访问variablesa ,它仍然是None (当foobar()被定义时,它将variables名称一劳永逸地绑定在a bar.pybar.py:a ,而不是另一个模块中定义的任何其他variables – 因为在所有导入的模块中可能会有许多variables)。 因此,最后一个None输出。

换句话说:这个错误的想法很容易做出来。 它在Python语言参考中被嘲讽地定义:使用对象而不是符号 。 我会build议Python语言参考使这更清晰,稀疏..

from表单不绑定模块名称:它通过标识符列表,在步骤(1)中find的模块中查找每个模块名称,并将名称空间中的名称绑定到find的对象

然而:

导入时,导入导入符号的当前值,并按照定义将其添加到您的名称空间。 您没有导入参考,您正在有效地导入一个值。

因此,要获取i的更新值,必须导入一个variables,该variables包含对该符号的引用。

换句话说,导入不像JAVA中的import ,C / C ++中的external声明或者PERL中的use条款。

相反,Python中的以下语句:

 from some_other_module import a as x 

更像 K&R C中的以下代码:

 extern int a; /* import from the EXTERN file */ int x = a; 

(注意:在Python的情况下,“a”和“x”本质上是对实际值的引用:你不是复制INT,而是复制引用地址)