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

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

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

谁能解释我的误解?

Suppose I have a package named bar, and it contains bar.py:

a = None

def foobar():
    print a

and __init__.py:

from bar import a, foobar

Then I execute this script:

import bar

print bar.a
bar.a = 1
print bar.a
bar.foobar()

Here’s what I expect:

None
1
1

Here’s what I get:

None
1
None

Can anyone explain my misconception?


回答 0

您正在使用from bar import aa在导入模块的全局范围(或​​发生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从交互式解释器访问模块时,这种东西是致命的。

You are using from bar import a. a becomes a symbol in the global scope of the importing module (or whatever scope the import statement occurs in).

When you assign a new value to a, you are just changing which value a points too, not the actual value. Try to import bar.py directly with import bar in __init__.py and conduct your experiment there by setting bar.a = 1. This way, you will actually be modifying bar.__dict__['a'] which is the ‘real’ value of a in this context.

It’s a little convoluted with three layers but bar.a = 1 changes the value of a in the module called bar that is actually derived from __init__.py. It does not change the value of a that foobar sees because foobar lives in the actual file bar.py. You could set bar.bar.a if you wanted to change that.

This is one of the dangers of using the from foo import bar form of the import statement: it splits bar into two symbols, one visible globally from within foo which starts off pointing to the original value and a different symbol visible in the scope where the import statement is executed. Changing a where a symbol points doesn’t change the value that it pointed too.

This sort of stuff is a killer when trying to reload a module from the interactive interpreter.


回答 1

这个问题困难的一个原因是,你有一个名为程序bar/bar.pyimport bar可导入bar/__init__.pybar/bar.py,取决于它完成,这使得它有点笨重跟踪哪些abar.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.aa)。

现在,当你做

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,后者仍然是Nonefoobar()定义后,它将一劳永逸地绑定变量名称,因此ain bar.pybar.py:a,而不是a另一个模块中定义的任何其他变量-因为a在所有导入的模块中可能有很多变量)。因此是最后一个None输出。

结论:最好是避免任何含糊之处import bar,由具有任何bar/bar.py模块(因为bar.__init__.py品牌目录bar/包已经,您还可以导入import bar)。

One source of difficulty with this question is that you have a program named bar/bar.py: import bar imports either bar/__init__.py or bar/bar.py, depending on where it is done, which makes it a little cumbersome to track which a is bar.a.

Here is how it works:

The key to understanding what happens is to realize that in your __init__.py,

from bar import a

in effect does something like

a = bar.a
# … where bar = bar/bar.py (as if bar were imported locally from __init__.py)

and defines a new variable (bar/__init__.py:a, if you wish). Thus, your from bar import a in __init__.py binds name bar/__init__.py:a to the original bar.py:a object (None). This is why you can do from bar import a as a2 in __init__.py: in this case, it is clear that you have both bar/bar.py:a and a distinct variable name bar/__init__.py:a2 (in your case, the names of the two variables just happen to both be a, but they still live in different namespaces: in __init__.py, they are bar.a and a).

Now, when you do

import bar

print bar.a

you are accessing variable bar/__init__.py:a (since import bar imports your bar/__init__.py). This is the variable you modify (to 1). You are not touching the contents of variable bar/bar.py:a. So when you subsequently do

bar.foobar()

you call bar/bar.py:foobar(), which accesses variable a from bar/bar.py, which is still None (when foobar() is defined, it binds variable names once and for all, so the a in bar.py is bar.py:a, not any other a variable defined in another module—as there might be many a variables in all the imported modules). Hence the last None output.

Conclusion: it is best to avoid any ambiguity in import bar, by not having any bar/bar.py module (since bar.__init__.py makes directory bar/ a package already, that you can also import with import bar).


回答 2

换一种说法:事实证明,这种误解很容易造成。 它是在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,而是在复制引用地址)

To put another way: Turns out this misconception is very easy to make. It is sneakily defined in the Python language reference: the use of object instead of symbol. I would suggest that the Python language reference make this more clear and less sparse..

The from form does not bind the module name: it goes through the list of identifiers, looks each one of them up in the module found in step (1), and binds the name in the local namespace to the object thus found.

HOWEVER:

When you import, you import the current value of the imported symbol and add it to your namespace as defined. You are not importing a reference, you are effectively importing a value.

Thus, to get the updated value of i, you must import a variable that holds a reference to that symbol.

In other words, importing is NOT like an import in JAVA, external declaration in C/C++ or even a use clause in PERL.

Rather, the following statement in Python:

from some_other_module import a as x

is more like the following code in K&R C:

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

int x = a;

(caveat: in the Python case, “a” and “x” are essentially a reference to the actual value: you’re not copying the INT, you’re copying the reference address)