The problem is that two instances of the variable X are created in such a set-up: one in a.py
and another in b.py
. The problem also occurs in this example that reduces it to the essence — it is not related to creating threads:
Problem in most simple form
File a.py
:
X = "original value"
import b
if __name__ == '__main__':
b.monitor()
print ('A', X)
File b.py
:
import a
def monitor():
print ('B', a.X)
a.X = "new value"
print ('B', a.X)
When running a.py
the output is:
B original value
B new value
A original value
If the same X
were accessed, then the last line of the output would have read:
A new value
Explanation
This happens because import
creates new instances of all global names therein. It will do this only upon the first time import a
is encountered, and it really is the first time here. The module created by execution of a.py
is named __main__
, not a
. Since this name is different from a
, import a
will really import the module, and not just reference the already loaded __main__
module. See also the Python documentation for a description of how module names are resolved.
As a consequence the names in these two modules are distinct; import a
does not make the __main__
names accessible to the other module.
Solution
A quick solution is to replace the import a
statement in b.py
with an import __main__
statement, and use __main__.X
as the qualified name you want to access in b.py
. But this is not regarded the advised way to proceed.
A more robust way is to ensure the global variables are not defined in the executed script, but in an imported module — one that is imported by both a.py
and b.py
. The second import
will make the names available that were defined when the first import
was parsed:
File common.py
:
X = "original value"
File a.py
:
import common
import b
if __name__ == '__main__':
b.monitor()
print ('A', common.X)
File b.py
:
import common
def monitor():
print ('B', common.X)
common.X = "new value"
print ('B', common.X)
Now the output is:
B original value
B new value
A new value
Solution applied to your code
File common.py
:
import time
X = {}
def set():
global X
X[time.time()] = 1
def get():
global X
return X
File a.py
:
import common
import time
import b
if __name__ == '__main__':
b.monitor()
while True:
time.sleep(1)
common.set()
File b.py
:
import common
import threading
import time
def f():
while True:
time.sleep(1)
print common.get(), 'in b'
def monitor():
t = threading.Thread(target=f)
t.setDaemon(True)
t.start()
2
solved Access global variable across multiple modules and threads