Reputation: 30044
Summary: I have a script which exposes(1) a dict
and I need to modify this dict
from with another module
Note: Two great answers to a similar question explain a lot about variables scoping between modules but I fail to understand how this applies to my case.
In the code below, I expected that I will be able to modify the mainmodule.py
variable container
from within submodule.py
, which is not the case. Why?
How should I address the mainmodule
instance of container
from within submodule
?
The code for the main script
# mainmodule.py
# the main script which ultimately exposes the module variable 'container'
import submodule
container = dict()
class MainClass:
def __init__(self):
self.sub = submodule.SubClass()
def set(self, number):
print("main: container was {container}".format(container=container))
container['x'] = number
print("main: container is {container}".format(container=container))
def call(self, number):
self.sub.set(number)
if __name__ == "__main__":
mc = MainClass()
# updating container from this script
mc.set(1)
# updating container from another module
mc.call(2)
# again from this script, to check the updates
mc.set(3)
The code for the imported module
# submodule.py
import mainmodule
class SubClass:
def __init__(self):
pass
def set(self, number):
print("sub: container was {container}".format(container=mainmodule.container))
mainmodule.container['x'] = number
print("sub: container is {container}".format(container=mainmodule.container))
The output is
main: container was {}
main: container is {'x': 1}
sub: container was {}
sub: container is {'x': 2}
main: container was {'x': 1}
main: container is {'x': 3}
(1)The actual code uses bottle
to provide container
via json.dumps()
Upvotes: 3
Views: 1291
Reputation: 156278
Staring at your code for a bit, I think i know what might be throwing you off. The python script invoked as python foo.py
will end up being a module (in sys.modules
) called __main__
. That means the bottom bit of your mainmodule.py
shows is loaded and compiled and run once, with __name__ == "__main__"
, which causes some things to happen. That module imports submodule
, which has not been imported yet, so that gets loaded and run.
submodule
in turn tries to import mainmodule
. Although that file has been executed before, it's not known to the interpreter by that module name, so mainmodule.py
gets run again, this time with __name__ == "mainmodule"
(which isn't the same as "__main__"
, so the if
suite at the bottom is skipped).
That means you have two copies of container
, one in the module who's name is __main__
, and one in a module named mainmodule
. The fact that both are from a file called ./mainmodule.py
is not relevant.
There are a few ways to fix this. One is to always import the real immediately, as in:
# mainmodule.py
import submodule
class Foo:
pass
if __name__ == "__main__":
import mainmodule
mainmodule.Foo()
Another option is to move the code inside the if
to another file.
Upvotes: 5