2017-06-28 79 views
1

下面是描述某些不一致的Python(3.6)行爲的簡單文件。爲什麼Case 1Case 2運行,但Case 3失敗,儘管Case 3只是前兩種情況的合併?使用屬性裝飾器時Python中的行爲不一致

我提供了前兩種情況下的dis輸出。

import dis # Python bytecode disassembler 

class A(object): 
    def __init__(self): 
    self.x # In case 2, getting x results in a function call. 

    # CASE 1: Legal 
    def x(self): 
    y 
    pass 

    ''' 
    # CASE 2: Legal 
    @property 
    def x(self): 
    pass 
    ''' 

    ''' 
    # CASE 3: Illegal: 
    @property 
    def x(self): 
    y 
    pass 
    ''' 

if __name__ == '__main__': 
    a = A() 
    dis.dis(A) 

案例1個字節碼:

Disassembly of __init__: 
    5   0 LOAD_FAST    0 (self) 
       2 LOAD_ATTR    0 (x) 
       4 POP_TOP 
       6 LOAD_CONST    0 (None) 
       8 RETURN_VALUE 

Disassembly of x: 
    9   0 LOAD_GLOBAL    0 (y) 
       2 POP_TOP 

10   4 LOAD_CONST    0 (None) 
       6 RETURN_VALUE 

案例2字節碼:

Disassembly of __init__: 
    5   0 LOAD_FAST    0 (self) 
       2 LOAD_ATTR    0 (x) 
       4 POP_TOP 
       6 LOAD_CONST    0 (None) 
       8 RETURN_VALUE 
+4

在案例1,你是不是叫什麼; 'self.x'是一個未使用的函數引用。在情況3中,'self.x'實際上調用了定義的'x'的getter,它可能會試圖訪問一個未定義的全局名稱。 – chepner

+1

換句話說,您的評論「讓x導致函數調用」不正確。它評估爲一個你忽略調用的函數對象。 –

+0

該評論行不應該成爲這篇文章。如果我沒有弄錯,我認爲如果案例2未被註釋並且其他註釋掉了,那麼這條線就會適用。 – awalllllll

回答

1

這裏沒有矛盾。

當你實例化a = A()時,__init__被調用,其調用self.x,它將執行x的主體。在那個時候,沒有y inscope,所以你會得到一個異常。

+0

對不起,有什麼困惑?這可能應該是一個評論,而不是一個答案... –

+0

我很困惑,因爲我不明白什麼是不一致的海報的代碼?我編輯了答案。 – csl

1

感謝@ chepner的評論:

在案例1,你是不是叫什麼; self.x是未使用的函數引用 。在情況3中,self.x實際上調用x的已定義的獲取器 ,這可能會試圖訪問未定義的全局名稱( )。

案例3中由行self.x引起的行爲與案例1基本上不同,因爲案例1不會調用任何內容 - 它只是評估對函數的引用。

另一方面,在案例3中self.x執行x方法的正文,導致未定義的y錯誤。

爲了證實@ chepner的評論,我跑了的情況下1 a.x(),並得到了相同的錯誤的情況下,3