2011-08-17 66 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