Python 变量未在 if __name__ == '__main__' 之后定义
Python variables not defined after if __name__ == '__main__'
我正在尝试通过使用 multiprocessing
库中的 Pool
来分担查找符号列表的历史股价数据的任务。
在我尝试使用我取回的数据之前,这非常有效。我定义了 hist_price
函数,它输出到字典列表 pcl
。我可以 print(pcl)
并且它一直完美无缺,但是如果我在 if __name__=='__main__':
块之后尝试 print(pcl)
,它会爆炸说 pcl
未定义。我试过在几个地方声明 global pcl
,但没有什么区别。
from multiprocessing import Pool
syms = ['List', 'of', 'symbols']
def hist_price(sym):
#... lots of code looking up data, calculations, building dicts...
stlh = {"Sym": sym, "10D Max": pcmax, "10D Min": pcmin} #simplified
return stlh
#global pcl
if __name__ == '__main__':
pool = Pool(4)
#global pcl
pcl = pool.map(hist_price, syms)
print(pcl) #this works
pool.close()
pool.join()
print(pcl) #says pcl is undefined
#...rest of my code, dependent on pcl...
我也试过删除 if __name__=='__main__':
块,但它给了我一个 RunTimeError 告诉我专门把它放回去。有没有其他方法可以调用 if
块之外的变量?
我认为您的问题分为两部分。第一个是"what's wrong with pcl
in the current code?",第二个是"why do I need the if __name__ == "__main__"
guard block at all?".
让我们按顺序解决它们。 pcl
变量的问题在于它仅在 if
块中定义,因此如果模块加载时没有 运行 作为脚本(这是设置 __name__ == "__main__"
),后面代码运行s.
时不会定义
要解决此问题,您可以更改代码的结构。最简单的修复方法是在 if __name__ == "__main__"
块中也保护使用 pcl
的代码的其他位(例如,可能将它们全部缩进到当前块下)。另一种解决方法是将使用 pcl
的代码放入函数中(可以在保护块外声明),然后从 if __name__ == "__main__"
块中调用函数。那看起来像这样:
def do_stuff_with_pcl(pcl):
print(pcl)
if __name__ == "__main__":
# multiprocessing code, etc
pcl = ...
do_stuff_with_pcl(pcl)
至于为什么会出现这个问题,最终的原因是在Windows上使用了multiprocessing
模块。您可以在 the documentation.
中阅读有关该问题的信息
当 multiprocessing 为其 Pool
创建一个新进程时,它需要使用当前模块状态的副本来初始化该进程。因为 Windows 没有 fork
(它会自动将父进程的内存复制到子进程中),所以 Python 需要从头开始设置所有内容。在每个子进程中,它从其文件中加载模块,如果您模块的顶级代码尝试创建一个新的 Pool
,您将遇到递归情况,其中每个子进程都会开始生成一个全新的一组自己的子进程。
multiprocessing
代码有一些防范措施,我认为(所以你不会 fork bomb 自己出于简单的粗心),但你仍然需要自己做一些工作,通过使用 if __name__ == "__main__"
来保护子进程中不应该 运行 的任何代码。
我正在尝试通过使用 multiprocessing
库中的 Pool
来分担查找符号列表的历史股价数据的任务。
在我尝试使用我取回的数据之前,这非常有效。我定义了 hist_price
函数,它输出到字典列表 pcl
。我可以 print(pcl)
并且它一直完美无缺,但是如果我在 if __name__=='__main__':
块之后尝试 print(pcl)
,它会爆炸说 pcl
未定义。我试过在几个地方声明 global pcl
,但没有什么区别。
from multiprocessing import Pool
syms = ['List', 'of', 'symbols']
def hist_price(sym):
#... lots of code looking up data, calculations, building dicts...
stlh = {"Sym": sym, "10D Max": pcmax, "10D Min": pcmin} #simplified
return stlh
#global pcl
if __name__ == '__main__':
pool = Pool(4)
#global pcl
pcl = pool.map(hist_price, syms)
print(pcl) #this works
pool.close()
pool.join()
print(pcl) #says pcl is undefined
#...rest of my code, dependent on pcl...
我也试过删除 if __name__=='__main__':
块,但它给了我一个 RunTimeError 告诉我专门把它放回去。有没有其他方法可以调用 if
块之外的变量?
我认为您的问题分为两部分。第一个是"what's wrong with pcl
in the current code?",第二个是"why do I need the if __name__ == "__main__"
guard block at all?".
让我们按顺序解决它们。 pcl
变量的问题在于它仅在 if
块中定义,因此如果模块加载时没有 运行 作为脚本(这是设置 __name__ == "__main__"
),后面代码运行s.
要解决此问题,您可以更改代码的结构。最简单的修复方法是在 if __name__ == "__main__"
块中也保护使用 pcl
的代码的其他位(例如,可能将它们全部缩进到当前块下)。另一种解决方法是将使用 pcl
的代码放入函数中(可以在保护块外声明),然后从 if __name__ == "__main__"
块中调用函数。那看起来像这样:
def do_stuff_with_pcl(pcl):
print(pcl)
if __name__ == "__main__":
# multiprocessing code, etc
pcl = ...
do_stuff_with_pcl(pcl)
至于为什么会出现这个问题,最终的原因是在Windows上使用了multiprocessing
模块。您可以在 the documentation.
当 multiprocessing 为其 Pool
创建一个新进程时,它需要使用当前模块状态的副本来初始化该进程。因为 Windows 没有 fork
(它会自动将父进程的内存复制到子进程中),所以 Python 需要从头开始设置所有内容。在每个子进程中,它从其文件中加载模块,如果您模块的顶级代码尝试创建一个新的 Pool
,您将遇到递归情况,其中每个子进程都会开始生成一个全新的一组自己的子进程。
multiprocessing
代码有一些防范措施,我认为(所以你不会 fork bomb 自己出于简单的粗心),但你仍然需要自己做一些工作,通过使用 if __name__ == "__main__"
来保护子进程中不应该 运行 的任何代码。