2011-08-17 55 views
3

当我尝试运行使用runpy模块加载的文件中定义的方法时,出现意外的行为。这些方法看不到在该方法外定义的任何变量(包括导入的模块)。这里是我正在做它:闭包如何在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将构成重新封闭,X和y。

但是,相反,我得到:

world 
hello 
world 
No re 
None 
None 

看起来再没有即使它应该是正常的闭合行为FN内定义。 x和y更加陌生,因为它们看起来是被定义的,但被设置为None。

为什么会这样以及闭包如何与runpy一起工作?我如何实现正常行为,使fn能够“看到”外部变量?

回答

4

好的,这是对Python处理模块的方式的一种好奇,我知道这些模块,但没有完全理解。我在IPython上工作时碰到过它,在a comment中有解释。

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

我不知道是否有方法与runpy。 IPython使用一些复杂的代码来重新使用模块对象来运行其他文件,缓存__dict__的副本以保持其中的引用处于活动状态。如果你有兴趣,请看magic_run function