问题:如何从另一个模块更改模块变量?
假设我有一个名为的软件包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
谁能解释我的误解?
回答 0
您正在使用from bar import a
。a
在导入模块的全局范围(或发生import语句的任何范围)中成为符号。
当您为指定新值时a
,您也只是在更改哪些值a
,而不是实际值。尝试bar.py
直接使用import bar
in 导入,__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
该符号开始指向原始值,而另一个符号在import
执行该语句的范围内可见。更改符号指向的位置也不会更改其指向的值。
尝试reload
从交互式解释器访问模块时,这种东西是致命的。
回答 1
这个问题困难的一个原因是,你有一个名为程序bar/bar.py
:import bar
可导入bar/__init__.py
或bar/bar.py
,取决于它完成,这使得它有点笨重跟踪哪些a
是bar.a
。
下面是它的工作原理:
了解发生了什么事情的关键是要意识到自己__init__.py
,
from bar import a
实际上做了类似的事情
a = bar.a
# … where bar = bar/bar.py (as if bar were imported locally from __init__.py)
并定义一个新变量(bar/__init__.py:a
,如果需要的话)。因此,您的from bar import a
in __init__.py
会将名称绑定bar/__init__.py:a
到原始bar.py:a
对象(None
)。这就是为什么你可以做from bar import a as a2
的__init__.py
:在这种情况下,很显然,你有两个bar/bar.py:a
和一个不同的变量名bar/__init__.py:a2
(在你的情况下,这两个变量的名字恰好两者a
,但他们仍然生活在不同的命名空间:在__init__.py
,它们是bar.a
和a
)。
现在,当你做
import bar
print bar.a
您正在访问变量bar/__init__.py:a
(因为import bar
导入了your bar/__init__.py
)。这是您修改的变量(为1)。您没有触及variable的内容bar/bar.py:a
。所以当你随后做
bar.foobar()
您调用bar/bar.py:foobar()
,它将访问a
来自的变量bar/bar.py
,后者仍然是None
(foobar()
定义后,它将一劳永逸地绑定变量名称,因此a
in bar.py
是bar.py:a
,而不是a
另一个模块中定义的任何其他变量-因为a
在所有导入的模块中可能有很多变量)。因此是最后一个None
输出。
结论:最好是避免任何含糊之处import bar
,由不具有任何bar/bar.py
模块(因为bar.__init__.py
品牌目录bar/
包已经,您还可以导入import bar
)。
回答 2
换一种说法:事实证明,这种误解很容易造成。 它是在Python语言参考中偷偷地定义的:使用object而不是symbol。我建议使用Python语言参考使这一点更清晰,更稀疏。
的
from
形式不结合模块名称:它通过标识符的列表,看起来它们中的每一个向上的模块中,在步骤(1)中发现,并结合在本地命名空间中的名称对象从而找到。
然而:
导入时,将导入已导入符号的当前值,并将其添加到已定义的命名空间中。 您不是在导入参考,而是在有效导入值。
因此,要获取的更新值i
,必须导入一个变量,该变量包含对该符号的引用。
换句话说,导入import
与JAVA中的,external
C / C ++中的声明甚use
至PERL中的子句都不一样。
而是在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,而是在复制引用地址)