如何从另一个模块更改模块变量?

时间:2010-08-21 06:34:37

标签: python import module

假设我有一个名为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

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

3 个答案:

答案 0 :(得分:73)

您正在使用from bar import aa成为导入模块的全局范围中的符号(或导入语句出现的任何范围)。

a分配新值时,您只是更改了a个值,而不是实际值。尝试直接使用bar.py中的import bar导入__init__.py,然后通过设置bar.a = 1在那里进行实验。这样,您实际上将修改bar.__dict__['a'],这是a在此上下文中的“真实”值。

这有三个层次,但bar.a = 1更改了a模块中bar的值,该值实际上来自__init__.py。它不会更改a看到的foobar的值,因为foobar位于实际文件bar.py中。如果您想更改它,可以设置bar.bar.a

这是使用from foo import bar声明的import形式的危险之一:它将bar拆分为两个符号,一个从foo内开始全局可见off指向原始值以及在执行import语句的范围内可见的不同符号。更改符号指向的位置不会更改它指向的值。

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

答案 1 :(得分:18)

这个问题的一个难点是你有一个名为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)

并定义一个新变量(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__.pybar/bar.py:a执行此操作的原因:在这种情况下,很明显您同时拥有bar/__init__.py:a2不同的变量名称{{1} (在你的情况下,两个变量的名称恰好都是a,但它们仍然存在于不同的名称空间中:在__init__.py中,它们是bar.a和{{1} })。

现在,当你做

a

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

bar/bar.py:a

你调用bar.foobar() ,它从bar/bar.py:foobar()访问变量a,它仍然是bar/bar.py(当定义None时,它会绑定变量名一次,总而言之,foobar()中的abar.py,而不是另一个模块中定义的任何其他bar.py:a变量 - 因为所有a变量都可能存在导入的模块)。因此,最后a输出。

答案 2 :(得分:10)

换句话说: 事实证明,这种误解很容易实现。 It is sneakily defined in the Python language reference:使用对象而不是符号。我建议Python语言参考使这更清晰,更少稀疏..

  

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

<强>但是:

导入时,导入导入符号的当前值,并将其添加到定义的命名空间中。 您没有导入引用,而是实际导入值。< /强>

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

换句话说,导入不像JAVA中的import,C / C ++中的external声明,甚至PERL中的use子句。

相反,Python中的以下语句:

from some_other_module import a as x

在K&amp; R C中更像 以下代码:

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

int x = a;

(警告:在Python的情况下,&#34; a&#34;和&#34; x&#34;基本上是对实际值的引用:你没有复制INT,你&#39; ;重新复制参考地址)