Answers:
您正在使用from bar import a。a在导入模块的全局范围(或发生import语句的任何范围)中成为符号。
当您为指定新值时a,您也只是在更改哪些值a,而不是实际值。尝试bar.py直接使用import barin 导入,__init__.py并通过设置在那里进行实验bar.a = 1。这样,您实际上将在此上下文中修改bar.__dict__['a']哪个是“实际”值a。
它有点复杂,分为三层,但是bar.a = 1更改了实际上是从派生a的模块中的值。它不会更改所看到的值,因为它存在于实际文件中。您可以设置是否要更改它。bar__init__.pyafoobarfoobarbar.pybar.bar.a
这是使用语句from foo import bar形式的危险之一import:它将分成bar两个符号,一个符号在全局范围内可见,从foo该符号开始指向原始值,而另一个符号在import执行该语句的范围内可见。更改符号指向的位置也不会更改其指向的值。
尝试reload从交互式解释器访问模块时,这种东西是致命的。
bar.bar.a方法在大多数用例中也无济于事。混合编译或模块加载以及运行时分配可能不是一个好主意,因为您最终会使自己(或其他使用您代码的人)感到困惑。尤其是在行为上有些不一致的语言中,就像python一样。
这个问题困难的一个原因是,你有一个名为程序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 ain __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()定义后,它将一劳永逸地绑定变量名称,因此ain bar.py是bar.py:a,而不是a另一个模块中定义的任何其他变量-因为a在所有导入的模块中可能有很多变量)。因此是最后一个None输出。
结论:最好是避免任何含糊之处import bar,由不具有任何bar/bar.py模块(因为bar.__init__.py品牌目录bar/包已经,您还可以导入import bar)。
换一种说法:事实证明,这种误解很容易造成。 它是在Python语言参考中偷偷地定义的:使用object而不是symbol。我建议使用Python语言参考使这一点更清晰,更稀疏。
的
from形式不结合模块名称:它通过标识符的列表,看起来它们中的每一个向上的模块中,在步骤(1)中发现,并结合在本地名称空间中的名称对象从而找到。
然而:
导入时,将导入已导入符号的当前值,并将其添加到已定义的命名空间中。 您不是在导入参考,而是在有效导入值。
因此,要获取的更新值i,必须导入一个变量,该变量包含对该符号的引用。
换句话说,导入import与JAVA中的,externalC / 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,而是在复制引用地址)
import比Java更清洁,因为名称空间/作用域应始终保持适当的分隔,并且永远不会以意想不到的方式相互干扰。如此处所示:更改对象与名称空间中名称的绑定(请参阅:将某些内容关联到模块的全局属性)不会影响Python中的其他名称空间(请参阅:已导入的引用)。但这在Java等中也是如此。在Python中,您只需要了解导入的内容,而在Java中,您还必须了解其他模块,以防以后更改此导入的值。