2012-08-29 26 views
2

我想要在exec方法中使用字典的子類。 最終,我想本地函數有一個自定義名稱範圍的行爲。exec()方法中的自定義名稱空間的子類python字典

在下面的代碼中,功能b()確實具有正確的globals()字典可用,但是在解析z時無法搜索它。

功能b()先不搜locals()然後globals()

非常令人費解。 任何幫助表示讚賞。

t = ''' 
def b(): 
# return (globals()['z']) #works 
    return z #fails 

b() 
''' 

class MyDict(dict): 
    def __init__(self, g): 
     dict.__init__(self) 
     self.my_g = g 


    def __getitem__(self, key): 
     print("GET ", key) 
     try: 
      val = dict.__getitem__(self, key) 
     except: 
      print("GET exception1") 
      val = self.my_g[key] 
     return val 


g = {'z':123} 

md = MyDict(g) 

#fails to find z 
exec(t, md, md) 

#works 
#exec(t, g, g) 

輸出

GET b 
Traceback (most recent call last): 
    File "/project1/text12", line 31, in <module> 
    File "<string>", line 6, in <module> 
    File "<string>", line 4, in b 
NameError: global name 'z' is not defined 
+0

返回z失敗,因爲沒有變量z。你說return(globals()['z'])有效,返回z時你想完成什麼? –

+0

我希望從傳入的全局字典中解析出z,正如下面的答案中所述。乾杯 – rbairos

回答

4

蟒蛇3.3之前,您不能使用自定義dict子類的exec語句的globals值。執行編譯代碼的底層C代碼直接訪問底層C結構,忽略任何自定義鉤子。

換句話說,當代碼做了GLOBAL_LOAD操作者(如在你的函數bz的情況下)中,C字節碼評估循環accessess使用C API,繞過任何蟒覆蓋在當前幀中的globals結構。

這是記錄在exec() function documentation爲:

如果只提供全局,它必須是一個字典,這將被用於全球和局部變量。如果給出全局變量給出了當地人,它們分別用於全局變量和局部變量。如果提供,當地人可以是任何映射對象。

此限制在Python 3.3中已經放寬,請參閱issue 14385。文檔尚未更新,但字節碼評估循環已更新,以在回到C API訪問之前測試自定義映射。如果使用自定義映射,則使用PyObject_GetItem方法,該方法將在自定義類上調用__getitem__

+0

非常感謝。我沒有機會回到我原來的工作,但它看起來不錯。再次感謝 - 羅布 – rbairos

+0

對不起@ martijn-pieters,它尚未完成。您的添加適用於查找本地範圍內的變量,但不適用於原始範例中的變量範圍。 我也使用Python 3.2,如果相關的。 換句話說: T = '打印(Z)' 現在工作 但: T = '' ' DEF B(): 回報ž B() ''' 仍然失敗。 任何有關如何獲得函數範圍來搜索全局字典的案例,就像我直接傳入g時一樣?謝謝。 – rbairos

+0

@ rbairos:這就是我在上半場解釋的;函數範圍中的未綁定變量總是在'global()'範圍內查找。這裏沒有模塊局部範圍,通常也將其放在'global()'範圍內。 –

相關問題