I'm having trouble understanding why importing a global variable from another module works as expected when using import, but when using from x import * the global variable doesn't appear to update within its own module
Imagine I have 2 files, one.py:
def change(value):
global x
x = value
x = "start"
and two.py:
from one import *
print x
change("updated")
print x
I'd expect:
start
updated
But I get...
start
start
If I import the module normally it works as expected
import one
print one.x
one.change("updated")
print one.x
Result...
start
updated
Given that I can't change ony.py's use of global variables (not my fault), and two.py is meant to be a sort of wrapper* around one.py, I'd really like to avoid using the one. namespace throughout two.py for the sake of one stubborn variable.
If it's not possible a novice-level explantion of what's going on might help me avoid getting stuck like this again. I undertand that one.x is getting updated, but two.x isn't respecting the updates, but I don't know why.
You can think of a package as a dict. Every function and variable in a package is listed as a key in that dict which you can view using globals().
When you import an object from another package, you copy a reference to the object into your own package under a name (usually the same, different if you import <var> as <name>).
By setting the value in the other package, you overwrite the key in that package with a new value, but you leave your reference pointing to the old one.
We can demonstrate the process using dicts as an analogy:
# Our 'packages'
one = {'x': 'start'}
two = {}
# Equivalent of our import
two['x'] = one['x']
# Variable updated in `one'
one['x'] = 'updated'
# ... and accessed in `two`
print(two['x']) # Still 'start'
We would not expect the two dict to be updated just because we overwrote a value in one.
You can modify the object as long as you don't break the pointer by overwriting the variable. For example if x was a dict, you could change a value inside the dict and the two variables would still point to the same object.
Alternatively you could attach a variables to the function like this:
def change(value):
change.x = value
This does the same work by ensuring we are mutating the same object.
A better answer yet might be to wrap both items in an object if they need to travel together:
class Changer:
x = 'start'
@classmethod
def change(cls, value):
cls.x = value
At this point however, we could modify the value directly as an attribute:
Changer.x = 'updated'
Which might be the simplest.
You can import twice from the same module like this:
from one import *
import one
print one.x
change("updated")
print one.x
basically by attaching module name you are forcing the code to use the imported module's variable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With