这个Python类变量作用域行为是完全意想不到的,而且很奇怪。这是怎么回事?
问题描述:
好吧,这其中有我撕裂我的头发:这个Python类变量作用域行为是完全意想不到的,而且很奇怪。这是怎么回事?
我有一个多进程的程序,有独立的工人在每一个给定的任务工作。
当KeyboardInterrupt出现时,我希望每个工作人员将其内部状态保存到一个文件中,以便它可以继续下一次停止的位置。
无论其...
它看起来像它包含关于在此之前可能发生的状态消失信息字典!
怎么样? exit()函数正在访问更多的全局范围版本的字典......事实证明,各种run()(和从属于run())函数已经创建了它们自己的变量版本。
没什么奇怪有关...
除...
他们都已经使用了自我。关键词。
其中,如果我的理解是正确的,应该意味着他们总是访问变量的实例范围版本...不创建它们自己的!
下面的代码的简化版本:
import multiprocessing
import atexit
import signal
import sys
import json
class Worker(multiprocessing.Process):
def __init__(self, my_string_1, my_string_2):
# Inherit the __init_ from Process, very important or we will get errors
super(Worker, self).__init__()
# Make sure we know what to do when called to exit
atexit.register(self.exit)
signal.signal(signal.SIGTERM, self.exit)
self.my_dictionary = {
'my_string_1' : my_string_1,
'my_string_2' : my_string_2
}
def run(self):
self.my_dictionary = {
'new_string' : 'Watch me make weird stuff happen!'
}
try:
while True:
print(self.my_dictionary['my_string_1'] + " " + self.my_dictionary['my_string_2'])
except (KeyboardInterrupt, SystemExit):
self.exit()
def exit(self):
# Write the relevant data to file
info_for_file = {
'my_dictionary': self.my_dictionary
}
print(info_for_file) # For easier debugging
save_file = open('save.log', 'w')
json.dump(info_for_file, save_file)
save_file.close()
# Exit
sys.exit()
if __name__ == '__main__':
strings_list = ["Hello", "World", "Ehlo", "Wrld"]
instances = []
try:
for i in range(len(strings_list) - 2):
my_string_1 = strings_list[i]
my_string_2 = strings_list[i + 1]
instance = Worker(my_string_1, my_string_2)
instances.append(instance)
instance.start()
for instance in instances:
instance.join()
except (KeyboardInterrupt, SystemExit):
for instance in instances:
instance.exit()
instance.close()
上运行,我们得到以下回溯...
Process Worker-2:
Process Worker-1:
Traceback (most recent call last):
File "/usr/lib/python3.5/multiprocessing/process.py", line 249, in _bootstrap
self.run()
Traceback (most recent call last):
File "/usr/lib/python3.5/multiprocessing/process.py", line 249, in _bootstrap
self.run()
File "<stdin>", line 18, in run
File "<stdin>", line 18, in run
KeyError: 'my_string_1'
KeyError: 'my_string_1'
换句话说,即使在被明确添加的关键my_string_1 init,run()函数正在访问self.my_dictionary的新版本,该版本不包含该密钥!
同样,如果我们用一个普通变量处理(my_dictionary而不是self.my_dictionary),但我认为self.variables总是实例范围,这将有望...
这到底是怎么回事?
答
你的问题基本上可以由以下表示:
class Test:
def __init__(self):
self.x = 1
def run(self):
self.x = 2
if self.x != 1:
print("self.x isn't 1!")
t = Test()
t.run()
注意什么run
在做什么。
您有不兼容的数据覆盖您的实例成员self.my_dictionary
当你写
self.my_dictionary = {
'new_string' : 'Watch me make weird stuff happen!'
}
然后尝试使用不兼容的数据时,你说
print(self.my_dictionary['my_string_1']...
这不正是明确你的目的是什么,当你覆盖my_dictionary
,但这就是为什么你会收到错误。你需要重新思考你的逻辑。
谢谢,我想你明白了,而且你是正确的,我的代码本来可以更小。我不确定多处理方面是否可能是问题的一部分。 我的意思是设置self.my_dictionary [“new_string”] ='看我做出奇怪的事情发生!' ... 在原始演示代码中进行修正会产生预期结果。 不幸的是,在原始程序中进行相同的修正不会!我仍然得到一个'schitzophrenic变量'的效果,当程序退出时,数据运行()添加到字典中不存在... – right2clicky
@ right2clicky您必须在别处做类似的事情。简而言之,你所描述的效果不仅仅发生在自己身上。尝试找出演示不同的地方。 – Carcigenicate
嗯,我搜索了self.my_dictionary的等效变量的代码,以下是我的操作: __init__:初始化为{} ... body函数:len()... body函数:。 append(somedata)... body function:.pop(index)... body function:.extend(somedata)... ...以及从变量中获取数据的一些事情。而已! 我不知道这些如何会打破或覆盖它... – right2clicky