2011-01-20 25 views
3

asking a question about reflection我問:python函數/方法調用有什麼靜態的嗎?

好的答案。但是說myobject.foo()x = getattr(myobject, "foo"); x();有區別。即使它只是化妝品。在第一個foo()靜態編譯。在第二種情況下,字符串可以通過多種方式生成。 - 喬1小時前

這得到了答案:

嗯,馬鈴薯/馬鈴薯...在python,niether是靜態編譯,所以它們都或多或少等價。 - SWeko 1小時前

我知道Python對象的成員都存儲在一個字典,這一切都是動態的,但我認爲,鑑於以下代碼:

class Thing(): 
    def m(self): 
    pass 

t = Thing() 

下面的代碼會以某種方式生成.pyc文件時獲得靜態編譯:

t.m() 

即編譯器知道的m()地址,所以沒有點運行時綁定。這或運行時會緩存後續查找。

而這將總是涉及擊中詞典:

meth = getattr(t, "m") 
meth() 

是否所有調用視爲字典字符串查找?或者這兩個例子實際上是相同的嗎?

回答

7

他們並不完全一樣,但它們都是字典查找,如可以用反彙編dis.dis顯示。

特別是,請注意LOAD_ATTR指令通過名稱動態查找屬性。根據文檔,它「用getattr(TOS, co_names[namei])」替代了TOS [棧頂​​]。

>>> from dis import dis 
>>> dis(lambda: t.m()) 
    1   0 LOAD_GLOBAL    0 (t) 
       3 LOAD_ATTR    1 (m) 
       6 CALL_FUNCTION   0 
       9 RETURN_VALUE   
>>> dis(lambda: getattr(t, 'm')()) 
    1   0 LOAD_GLOBAL    0 (getattr) 
       3 LOAD_GLOBAL    1 (t) 
       6 LOAD_CONST    0 ('m') 
       9 CALL_FUNCTION   2 
      12 CALL_FUNCTION   0 
      15 RETURN_VALUE   
+0

+1爲非常有趣的答案! – rubik 2011-01-20 12:54:38

3

所有調用都被視爲字典查找(好吧,內部python可能會做某種優化,但就其工作原理而言,您可以假設它們是字典查找)。

Python中沒有靜態編譯。這是可能的,即使這樣做:

t = Thing() 
t.m = lambda : 1 
t.m() 
1

不僅類可以在運行時修改(如HS example);但即使是class的關鍵字是「執行」在運行時:

類定義是一個可執行 聲明。它首先評估 繼承列表(如果存在)。繼承列表中的每個 項目應該 評估爲允許子類化的類對象或類型 類型。 類的套件然後在 新執行框架中執行(請參見 命名和綁定一節),使用新創建的本地名稱空間 和原始全局命名空間 。 (通常,該套件僅包含功能 定義。)當類的套件 完成執行時,其執行 幀將被丟棄,但其本地 名稱空間被保存。 [4]然後使用基類的繼承 列表和 屬性字典的 保存的本地名稱空間創建類對象 。類名 綁定到 原始本地名稱空間中的此類對象。

Python language reference 7.7: Class Definitions

換句話說,在啓動時,解釋器執行class塊中的代碼,並保持所得到的上下文。在編譯時,無法知道類將如何。

2

這取決於您是在詢問Python的語言還是特定的實現(如CPython)。

語言本身並沒有說這兩者是相同的,所以可能會以某種方式優化直接屬性訪問。然而,Python的動態特性使得難以一致地實現這一點,所以在CPython中,兩者實際上是完全相同的。

說了這麼多,直接t.m()可以是大約快兩倍,使用getattr(),因爲它涉及到一個字典查詢,而不是你getattr()得到兩個:即全局名稱getattr()本身在字典中查找。

1

使用getattr您可以訪問名稱不是有效標識符的屬性,但我不確定是否有使用像這樣的屬性的用例,而不是使用字典。

>>> setattr(t, '3', lambda : 4) 
>>> t.3() 
    File "<stdin>", line 1 
    t.3() 
    ^
SyntaxError: invalid syntax 
>>> getattr(t, '3')() 
4 
相關問題