Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Global variable imported from a module does not update - why?

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.

like image 287
Spacey Avatar asked Jan 17 '26 03:01

Spacey


2 Answers

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.

An analogy with dicts

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.

What you can do about it

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.

like image 135
Jon Betts Avatar answered Jan 19 '26 18:01

Jon Betts


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.

like image 22
KawaiKx Avatar answered Jan 19 '26 16:01

KawaiKx



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!