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

shi*_*ino 85 python import module

假设我有一个名为的包bar,它包含bar.py:

a = None

def foobar():
    print a
Run Code Online (Sandbox Code Playgroud)

并且__init__.py:

from bar import a, foobar
Run Code Online (Sandbox Code Playgroud)

然后我执行这个脚本:

import bar

print bar.a
bar.a = 1
print bar.a
bar.foobar()
Run Code Online (Sandbox Code Playgroud)

这就是我的期望:

None
1
1
Run Code Online (Sandbox Code Playgroud)

这是我得到的:

None
1
None
Run Code Online (Sandbox Code Playgroud)

任何人都能解释我的错误观念吗?

aar*_*ing 82

你在用from bar import a.a成为导入模块的全局范围中的符号(或导入语句出现的任何范围).因此,当您为其分配新值时a,您只需更改哪个值a,而不是实际值.尝试导入bar.py直接与import bar__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从交互式解释器尝试模块时,这种东西是杀手.


Eri*_*got 20

这个问题困难的一个原因是,你有一个名为程序bar/bar.py:import bar可导入bar/__init__.pybar/bar.py,取决于它完成,这使得它有点笨重跟踪哪些abar.a.

下面是它的工作原理:

理解发生的事情的关键是要意识到在你的__init__.py,

from bar import a
Run Code Online (Sandbox Code Playgroud)

实际上做了类似的事情

a = bar.a  # … with bar = bar/bar.py (as if bar were imported locally from __init__.py)
Run Code Online (Sandbox Code Playgroud)

并定义一个新变量(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:在这种情况下,很显然,你有两个bar/bar.py:a和一个不同的变量名bar/__init__.py:a2(在你的情况下,这两个变量的名称只是碰巧都为a,但他们仍然生活在不同的命名空间:在__init__.py,他们是bar.aa).

现在,当你这样做

import bar

print bar.a
Run Code Online (Sandbox Code Playgroud)

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

bar.foobar()
Run Code Online (Sandbox Code Playgroud)

你叫bar/bar.py:foobar(),它访问的变量abar/bar.py,这仍然是None(时foobar()被定义,它绑定变量名一劳永逸的,所以abar.pyIS bar.py:a,没有任何其他a的另一模块定义的变量可能有许多a在所有导入的模块变量).因此最后的None输出.


Mar*_*tos 10

换句话说:结果证明这种误解很容易. 它在Python语言参考中被巧妙地定义:使用object而不是symbol.我建议Python语言参考使这更清晰,更少稀疏..

from形式不结合模块名称:它通过标识符的列表,看起来它们中的每一个向上在步骤(1)中发现的模块中,并且在本地名称空间中的结合名称对象从而找到.

然而:

导入时,导入导入符号的当前值,并将其添加到定义的命名空间中. 您没有导入引用,您实际上是在导入值.

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

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

相反,Python中的以下语句:

from some_other_module import a as x
Run Code Online (Sandbox Code Playgroud)

是更喜欢在K&R C以下代码:

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

int x = a;
Run Code Online (Sandbox Code Playgroud)

(警告:在Python的情况下,"a"和"x"本质上是对实际值的引用:你没有复制INT,你正在复制引用地址)

  • 我必须非常坚决地反对。导入/包含/使用在使用参考形式而不是价值形式方面有着悠久的历史,这对于其他所有语言都是如此。 (2认同)
  • 该死的,我点击了返回...有一个期望通过引用导入(按照@OP).事实上,一个新的Python程序员,无论多么有经验,都必须以"向外看"的方式告诉他们.这绝不应该发生:基于常见用法,Python走错了路.如果需要,创建"导入值",但不要在导入时将符号与值混淆. (2认同)