当我尝试运行使用runpy模块加载的文件中定义的方法时出现意外行为。这些方法没有看到在该方法之外定义的任何变量(包括导入的模块)。我是这样做的:
#test.py
import runpy
env = runpy.run_path('test', {'y':'world'})
env['fn']()
〜
#test
import re
print(re.compile(r'^hello', re.IGNORECASE).sub('', "hello world"))
x = "hello"
print(x)
print(y)
def fn():
try:
print(re.compile(r'^hello', re.IGNORECASE).sub('', "hello world"))
except:
print("No re")
try:
print(x)
except:
print("No x")
try:
print(y)
except:
print("No y")
我对test.py的预期输出是:
world
hello
world
world
hello
world
因为fn会形成re,x和y的闭包。
然而,我得到了:
world
hello
world
No re
None
None
看起来re没有在fn中定义,即使它应该是正常的闭包行为。 x和y甚至更奇怪,因为它们似乎已定义但设置为None。
为什么这样以及闭包如何与runpy一起使用?如何才能实现fn可以“看到”外部变量的正常行为?
答案 0 :(得分:4)
好的,这是对Python处理模块的好奇心,我知道但不完全理解。我在处理IPython时遇到过它,在a comment中对它进行了解释。
当Python运行模块时,它会生成一个模块对象,其属性是模块中的全局名称。当模块超出范围并被销毁时,这些属性将设置为None
。正如您所发现的那样,在函数中定义的代码将这些视为全局变量。您可以通过将def g(): return globals()
添加到您的文件,然后调用env["g"]()
。
我不知道runpy
是否有办法解决这个问题。 IPython使用一些复杂的代码来重用模块对象来运行其他文件,缓存其__dict__
的副本以使其中的引用保持活动状态。如果您有兴趣,请查看magic_run
function。