如何从另一个模块更改模块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 barforms的危险之一:它将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,而是复制引用地址)