如何从另一个模块更改模块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 a
。 a
在导入模块的全局范围(或任何导入语句所在的范围)中成为一个符号。 所以当你给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 bar
forms的危险之一:它将bar
拆分为两个符号,一个从foo
中全局可见,从foo
开始指向原始值,另一个符号在import
语句被执行。 改变符号点的位置也不会改变它指向的值。
当试图从交互式解释器reload
模块时,这种东西是一个杀手。
这个问题的难点之一是你有一个名为bar/bar.py
的程序: import bar
导入bar/__init__.py
或bar/bar.py
,这取决于它在哪里完成,这使得它有点麻烦跟踪哪a
是bar.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.a
和a
)。
现在,当你这样做
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.py
是bar.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,而是复制引用地址)