当我尝试运行使用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才能“看到”外部变量?
发布于 2011-08-17 20:25:55
好吧,这是对Python处理模块方式的好奇心,我知道但不完全理解。我在开发IPython时遇到过它,在a comment中解释了它。
当Python运行一个模块时,它会生成一个模块对象,该对象的属性是模块中的全局名称。当模块落入作用域之外并被销毁时,这些属性被设置为None。正如您所发现的,在函数中定义的代码会将这些视为全局变量。您可以通过向文件中添加def g(): return globals(),然后调用env["g"]()来演示这一点。
我不知道runpy有没有办法解决这个问题。IPython使用一些复杂的代码重用模块对象来运行其他文件,缓存其__dict__的副本以保持其中的引用处于活动状态。如果你感兴趣,可以看看magic_run function。
https://stackoverflow.com/questions/7092000
复制相似问题