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__" 来保护子进程中不应该 运行 的任何代码。