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

时间:2022-12-16 22:58:59

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?

有人能解释我的误解吗?

3 个解决方案

#1


56  

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). So when you assign a new value to a, you just change 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 are actually modifying bar.__dict__['a'] which is the 'real' value of a in this context.

您正在使用bar import a. a作为导入模块全局范围中的符号(或导入语句出现的任何范围)。当你给a赋一个新值时,你只需要改变a点的值,而不是实际值。尝试导入酒吧。与进口酒吧直接联系。py,通过设置bar来进行实验。一个= 1。这样,你实际上是在修改bar。__dict__[a],在此背景下a的“真实”价值。

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.

它有三层,但有条。a = 1改变了名为bar的模块中a的值,bar实际上是由__init__.py派生出来的。它不会改变foobar看到的值,因为foobar生活在实际的文件bar.py中。你可以设置bar.bar。a如果你想改变的话。

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.

这是一个危险的使用从foo进口bar的import语句形式:它将酒吧分为两个符号,一个从内部可见全球foo开始指向原始值和不同的符号出现在import语句执行的范围。改变符号点所在的位置并不会改变它所指向的值。

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

当试图从交互式解释器重新加载模块时,这类东西是一个杀手。

#2


15  

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.

这个问题的一个困难来源是您有一个名为bar/bar的程序。进口条进口条或进口条。py或酒吧/酒吧。py,这取决于它的位置,这使得跟踪哪个a是bara有点麻烦。

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  # … with 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).

并定义一个新变量(bar/__init__)。py:,如果你愿意)。因此,你从bar进口a到__。py酒吧/ __init__绑定名称。py:a到原来的酒吧。py:一个对象(没有)。这就是为什么可以从__init__中的bar导入a作为a2。在这种情况下,很明显你有两个bar/bar。py:a和一个不同的变量名bar/__init__。py:a2(在您的例子中,两个变量的名称恰好都是a,但是它们仍然存在于不同的名称空间:__init__中。py,酒吧。和一个)。

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/__init__。py:a(因为导入条导入你的bar/__init__.py)。这是您修改的变量(到1)。你没有接触到变量bar/bar.py:a。所以当你随后这么做的时候

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.

您可以调用bar/bar.py:foobar(),它从bar/bar访问变量a。py,仍然为None(当foobar()被定义时,它一次性地绑定变量名,因此a in bar。py是酒吧。py:a,不是任何其他在另一个模块中定义的变量——因为在所有导入的模块中都可能有许多变量)。因此最后没有输出。

#3


8  

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..

换句话说,这个误解很容易理解。在Python语言引用中偷偷地定义了它:使用对象而不是符号。我建议Python语言参考使这个更加清晰和稀疏。

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.

from form不绑定模块名称:它遍历标识符列表,在步骤(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 import in JAVA, external declaration in C/C++ or even a use clause in PERL.

换句话说,导入不像JAVA中的导入,也不像C/ c++中的外部声明,甚至不像PERL中的use子句。

Rather, the following statement in Python:

相反,Python中的以下语句:

from some_other_module import a as x

is more like the 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,而是复制引用地址)

#1


56  

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). So when you assign a new value to a, you just change 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 are actually modifying bar.__dict__['a'] which is the 'real' value of a in this context.

您正在使用bar import a. a作为导入模块全局范围中的符号(或导入语句出现的任何范围)。当你给a赋一个新值时,你只需要改变a点的值,而不是实际值。尝试导入酒吧。与进口酒吧直接联系。py,通过设置bar来进行实验。一个= 1。这样,你实际上是在修改bar。__dict__[a],在此背景下a的“真实”价值。

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.

它有三层,但有条。a = 1改变了名为bar的模块中a的值,bar实际上是由__init__.py派生出来的。它不会改变foobar看到的值,因为foobar生活在实际的文件bar.py中。你可以设置bar.bar。a如果你想改变的话。

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.

这是一个危险的使用从foo进口bar的import语句形式:它将酒吧分为两个符号,一个从内部可见全球foo开始指向原始值和不同的符号出现在import语句执行的范围。改变符号点所在的位置并不会改变它所指向的值。

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

当试图从交互式解释器重新加载模块时,这类东西是一个杀手。

#2


15  

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.

这个问题的一个困难来源是您有一个名为bar/bar的程序。进口条进口条或进口条。py或酒吧/酒吧。py,这取决于它的位置,这使得跟踪哪个a是bara有点麻烦。

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  # … with 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).

并定义一个新变量(bar/__init__)。py:,如果你愿意)。因此,你从bar进口a到__。py酒吧/ __init__绑定名称。py:a到原来的酒吧。py:一个对象(没有)。这就是为什么可以从__init__中的bar导入a作为a2。在这种情况下,很明显你有两个bar/bar。py:a和一个不同的变量名bar/__init__。py:a2(在您的例子中,两个变量的名称恰好都是a,但是它们仍然存在于不同的名称空间:__init__中。py,酒吧。和一个)。

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/__init__。py:a(因为导入条导入你的bar/__init__.py)。这是您修改的变量(到1)。你没有接触到变量bar/bar.py:a。所以当你随后这么做的时候

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.

您可以调用bar/bar.py:foobar(),它从bar/bar访问变量a。py,仍然为None(当foobar()被定义时,它一次性地绑定变量名,因此a in bar。py是酒吧。py:a,不是任何其他在另一个模块中定义的变量——因为在所有导入的模块中都可能有许多变量)。因此最后没有输出。

#3


8  

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..

换句话说,这个误解很容易理解。在Python语言引用中偷偷地定义了它:使用对象而不是符号。我建议Python语言参考使这个更加清晰和稀疏。

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.

from form不绑定模块名称:它遍历标识符列表,在步骤(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 import in JAVA, external declaration in C/C++ or even a use clause in PERL.

换句话说,导入不像JAVA中的导入,也不像C/ c++中的外部声明,甚至不像PERL中的use子句。

Rather, the following statement in Python:

相反,Python中的以下语句:

from some_other_module import a as x

is more like the 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,而是复制引用地址)