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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3536620/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 11:37:12  来源:igfitidea点击:

How to change a module variable from another module?

pythonimportmodule

提问by shino

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

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

a = None

def foobar():
    print a

and __init__.py:

__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?

谁能解释一下我的误解?

采纳答案by aaronasterling

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

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

When you assign a new value to a, you are just changing which value apoints too, not the actual value. Try to import bar.pydirectly with import barin __init__.pyand 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 ain this context.

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

It's a little convoluted with three layers but bar.a = 1changes the value of ain the module called barthat is actually derived from __init__.py. It does not change the value of athat foobarsees because foobarlives in the actual file bar.py. You could set bar.bar.aif you wanted to change that.

这三层波纹一点,但bar.a = 1改变的值a称为模块中bar,实际上是源自__init__.py。它不会改变a那个foobarsees的值,因为它foobar存在于实际文件中bar.pybar.bar.a如果你想改变它,你可以设置。

This is one of the dangers of using the from foo import barform of the importstatement: it splits barinto two symbols, one visible globally from within foowhich starts off pointing to the original value and a different symbol visible in the scope where the importstatement is executed. Changing a where a symbol points doesn't change the value that it pointed too.

这是使用语句from foo import bar形式的危险之一import:它分成bar两个符号,一个是全局可见的,从内部foo开始指向原始值,另一个符号在import执行语句的范围内可见。更改符号指向的位置并不会更改它所指向的值。

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

当试图reload从交互式解释器中获取模块时,这类东西是一个杀手。

回答by Eric O Lebigot

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

这个问题的一个困难来源是您有一个名为bar/bar.py:import bar导入bar/__init__.py或的程序bar/bar.py,这取决于它在哪里完成,这使得跟踪哪个abar.a.

Here is how it works:

下面是它的工作原理:

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

理解发生了什么的关键是要意识到,在你的__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 ain __init__.pybinds name bar/__init__.py:ato the original bar.py:aobject (None). This is why you can do from bar import a as a2in __init__.py: in this case, it is clear that you have both bar/bar.py:aand a distinctvariable 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.aand a).

并定义一个新变量(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)。

Now, when you do

现在,当你做

import bar

print bar.a

you are accessing variable bar/__init__.py:a(since import barimports 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/__init__.py:a(因为import bar导入了您的bar/__init__.py)。这是您修改的变量(到?1)。您没有触及 variable 的内容bar/bar.py:a。所以当你随后做

bar.foobar()

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

你调用bar/bar.py:foobar(), 它访问变量afrom bar/bar.py, which is still None(当foobar()被定义时,它会一劳永逸地绑定变量名,所以ain bar.pyis bar.py:a,而不是a在另一个模块中定义的任何其他变量——因为a在所有导入的模块中可能有很多变量)。因此最后的None输出。

Conclusion: it is best to avoid any ambiguity in import bar, by nothaving any bar/bar.pymodule (since bar.__init__.pymakes directory bar/a package already, that you can also import with import bar).

结论:最好import bar通过没有任何bar/bar.py模块来避免 中的任何歧义(因为bar.__init__.py目录bar/已经成为一个包,您也可以使用 导入import bar)。

回答by Mark Gerolimatos

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 objectinstead of symbol. I would suggest that the Python language reference make this more clear and less sparse..

换句话说:事实证明,这种误解很容易产生。 它在 Python 语言参考中偷偷地定义:使用object而不是symbol。我建议 Python 语言参考使这更清晰,更少稀疏..

The fromform 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 objectthus found.

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

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.

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

In other words, importing is NOT like an importin JAVA, externaldeclaration in C/C++ or even a useclause in PERL.

换句话说,导入不像importJAVA 中的,externalC/C++ 中的声明,甚至usePERL 中的子句。

Rather, the following statement in Python:

相反,Python 中的以下语句:

from some_other_module import a as x

is more likethe following code in K&R C:

是更喜欢在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)

(警告:在 Python 的情况下,“a”和“x”本质上是对实际值的引用:您不是在复制 INT,而是在复制引用地址)