我有两个python脚本相互导入并访问第一个脚本中定义的变量。但是在另一个模块中没有看到对此变量所做的更改。
可以复制行为的代码:
档案a.py
import time
import b
X = {}
def set():
global X
X[time.time()] = 1
def get():
global X
return X
if __name__ == '__main__':
b.monitor()
while True:
time.sleep(1)
set()
档案b.py
:
import threading
import time
from a import get
def f():
while True:
time.sleep(1)
print get(), 'in b'
def monitor():
t = threading.Thread(target=f)
t.setDaemon(True)
t.start()
使用python a.py
运行程序。结果是:
{} in b
{} in b
{} in b
...
预期产出:
{"1518106774": 1} in b
{"1518106774": 1, "1518106775": 1} in b
{"1518106774": 1, "1518106775": 1, "1518106776": 1} in b
... // etc
...其中键是time.time()
个字符串。
我认为应该能够在任何我们想要的地方引用全局变量X
。那么为什么X
中的b.f
未在[{1}}中更新,即使调用set
正在向其添加这些密钥?
答案 0 :(得分:2)
问题是在这样的设置中创建了变量X的两个实例:一个在a.py
中,另一个在b.py
中。在这个例子中也会出现问题,将其简化为本质 - 它与创建线程无关:
档案a.py
:
X = "original value"
import b
if __name__ == '__main__':
b.monitor()
print ('A', X)
档案b.py
:
import a
def monitor():
print ('B', a.X)
a.X = "new value"
print ('B', a.X)
运行a.py
时输出为:
B原值
B新值
原始值
如果访问了相同的X
,则输出的最后一行将显示为:
新值
这是因为import
在其中创建了所有全局名称的新实例。只有在第一次遇到import a
时它才会这样做,而这确实是第一次来到这里。由a.py
的执行创建的模块名为__main__
,而不是a
。由于此名称与a
不同,import a
将真正导入模块,而不仅仅是引用已加载的__main__
模块。另请参阅Python documentation以获取有关如何解析模块名称的说明。
因此,这两个模块中的名称是截然不同的; import a
不会使__main__
名称可供其他模块访问。
快速解决方案是使用import a
语句替换b.py
中的import __main__
语句,并使用__main__.X
作为您要在{{1}中访问的限定名称}}。但这不被视为advised way to proceed。
更健壮的方法是确保全局变量不是在执行的脚本中定义,而是在导入的模块中定义 - 由导入的模块 b.py
和{{1 }}。第二个a.py
将使解析第一个b.py
时定义的名称可用:
档案import
:
import
档案common.py
:
X = "original value"
档案a.py
:
import common
import b
if __name__ == '__main__':
b.monitor()
print ('A', common.X)
现在输出是:
B原值
B新值
新值
档案b.py
:
import common
def monitor():
print ('B', common.X)
common.X = "new value"
print ('B', common.X)
档案common.py
:
import time
X = {}
def set():
global X
X[time.time()] = 1
def get():
global X
return X
档案a.py
:
import common
import time
import b
if __name__ == '__main__':
b.monitor()
while True:
time.sleep(1)
common.set()
答案 1 :(得分:0)
import time
import b
X = {}
def set():
# global X
X[time.time()] = 1
def get():
global X
return X
if __name__ == '__main__':
b.monitor()
while True:
time.sleep(1)
import threading
import time
import a
def f():
while True:
time.sleep(1)
a.set()
print a.get(), 'in b'
def monitor():
t = threading.Thread(target=f)
t.setDaemon(True)
t.start()
{1518083438.771415: 1} in b
{1518083438.771415: 1, 1518083439.772717: 1} in b
{1518083440.773916: 1, 1518083438.771415: 1, 1518083439.772717: 1} in b
答案 2 :(得分:0)
我认为答案在于python并不真正允许全局变量。全局范围通常仅在同一模块中。因此,当另一个模块导入具有全局变量的模块时,将复制名称空间并创建具有相同原始值的变量。导入的Python模块不能直接访问导入它的模块中的全局变量,反之亦然。
您可能需要阅读1.2.5&部分。 1.15.6来自Norman Matloff的Quick and Painless Python PDF Tutorial