2

I am trying to use a global variable in a program but getting unexpected results. Example code is shown below. I tried to reduce the problem to its simplest components.

File a.py:

class Foo:
    def __init__(self, s1: str, s2: str):
        self.s1 = s1
        self.s2 = s2

    def __str__(self):
        return f'Foo(s1="{self.s1}", s2="{self.s2}")'

foo = Foo('first', 'second')

def set_foo(new_foo: Foo):
    global foo
    foo = new_foo
    print('Setting foo', foo)

File b.py:

from a import foo, Foo, set_foo

def tfunc():
    print('Old foo', foo)
    new_foo = Foo('third', 'fourth')
    set_foo(new_foo)
    print('New foo', foo)
    print(foo == new_foo)

tfunc()

When I run the program I get these results:

>python b.py
Old foo Foo(s1="first", s2="second")
Setting foo Foo(s1="third", s2="fourth")
New foo Foo(s1="first", s2="second")
False

Why is foo not getting set to the new value in the function tfunc?

1
  • Can you refactor this so that tfunc() explicitly takes a foo: Foo parameter, and returns the new Foo object, and eliminate the global variable entirely? This can get rid of a whole class of mysterious bugs from side effects you weren't expecting, resolve issues where tests fail because of a hidden dependency, and improve future-you's understanding of the code when you come back to look at it later. Commented Nov 10 at 23:44

2 Answers 2

4

When you do

from a import foo, Foo, set_foo

You're effectively doing a assignment, as though you had done

foo = [Import code]

This means that import is creating a new variable foo that just happens to currently point to the same object (Foo('first', 'second')) that the foo in a.py points to. When set_foo is called, that changes what object a.py's foo is refering to, but a reassignment does not affect other references that were referring to the same object:

a = 1
b = a  # Similar to your import
a = 2
print(b)  # Prints 1

The simplest solution here to do literally what you're going for is to just not create a new foo variable in b.py. Instead, do import a, then refer to foo using a.foo. Now, when you do a.foo, you're refering to the object held by the module directly.

Sign up to request clarification or add additional context in comments.

Comments

1

If you import something from another module, you get it as it exists at that moment. Further changes that may occur inside the module are not tracked.

If you want to refer to a global variable in another module and keep track of changes to it, you should refer to it inside its module namespace.

In other words, don't do this:

from mymodule import A

Do this:

import mymodule

print("The initial value of A is:", mymodule.A)

#
# ... some code that might change the value of A
#

print("The value of A is now:", mymodule.A)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.