How to change a modular variable from another module?

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 is what I expect:

 None 1 1 

Here is what I get:

 None 1 None 

Can anyone explain my fallacy?

+79
python import module
Aug 21 '10 at 6:34
source share
3 answers

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

When you assign a new value to a , you simply change which value of a indicates the point, not the actual value. Try importing bar.py directly with import bar in __init__.py and do your experiment there by setting bar.a = 1 . This way you will actually modify bar.__dict__['a'] which is the "real" value of a in this context.

It's a bit of bar.a = 1 with three layers, but bar.a = 1 changes the value of a in a module called bar which is actually derived from __init__.py . It does not change the meaning that a foobar sees, because foobar lives in the bar.py file bar.py . You can install bar.bar.a if you want to change this.

This is one of the dangers of using the from foo import bar form of the from foo import bar statement: it divides the bar into two characters: one foo that is visible globally from the inside, which begins to point to the original value, and the other symbol in the scope where the import statement is executed. Changing the point the symbol points to does not change the value it points to.

Such things kill when trying to reload module from an interactive interpreter.

+71
Aug 21 '10 at 6:41
source share

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

Here's how it works:

The key to understanding what is happening is the realization that, in __init__.py ,

 from bar import a 

essentially doing 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 want). So your from bar import a in __init__.py binds the name bar/__init__.py:a to the original bar.py:a ( None ) object. That 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 the different variable name bar/__init__.py:a2 (in your case the names of two variables just happen both of them are a , but they still live in different namespaces: in __init__.py they are bar.a and a ).

Now that you do

 import bar print bar.a 

you get access to the variable bar/__init__.py:a (since import bar imports your bar/__init__.py ). This is the variable you are modifying (up to 1). You do not touch the contents of the variable bar/bar.py:a . Therefore, when you subsequently perform

 bar.foobar() 

you call bar/bar.py:foobar() , which accesses the variable a from bar/bar.py , which is still None (when foobar() defined, it binds the variable names once and for all, therefore a in bar.py is bar.py:a , and not any other variable a defined in another module, since all imported modules can have many variables a ). Therefore, the last conclusion is None .

+18
Aug 21 '10 at 9:05 a.m.
source share

In other words: It turns out that this misconception is very easy to do. It is covertly defined in a Python reference: using an object instead of a character. I would suggest that the Python link makes this more clear and less sparse.

The from form does not associate the name of the module: it passes through the list of identifiers, each of them looks in the module found in (1) and associates the name in the local namespace with the object thus found.

HOWEVER:

When importing, you import the current value of the imported character and add it to your namespace as defined. You are not importing the link, you are actually importing the value.

Thus, in order to get the updated value of i , you must import a variable containing a link to this symbol.

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

Rather, the following statement in Python:

 from some_other_module import a as x 

looks more like the following code in K & RC:

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

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

+10
May 08 '17 at 18:47
source share



All Articles