3

当我尝试运行使用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 可以“看到”外部变量?

4

1 回答 1

4

好的,这是对 Python 处理模块方式的好奇,我知道但并不完全理解。我在使用 IPython 时遇到过它,在评论中对此进行了解释。

当 Python 运行一个模块时,它会生成一个模块对象,其属性是模块中的全局名称。当模块超出范围并被销毁时,这些属性将设置为None. 正如您所发现的,在函数中定义的代码然后将这些视为全局变量。您可以通过添加def g(): return globals()到您的文件中来证明这一点,然后调用env["g"]().

我不知道有没有办法解决这个问题runpy。IPython 使用一些复杂的代码来重用模块对象来运行其他文件,缓存其副本__dict__以保持其中的引用有效。如果您有兴趣,请查看该magic_run功能。

于 2011-08-17T12:25:55.163 回答