2016-08-18 60 views
1

根據official documentation,「數據屬性覆蓋具有相同名稱的方法屬性」。但是,我發現這是不正確的。數據屬性是否覆蓋Python中某個類的方法屬性?

class C: 
    x = 111 
    def x(self): 
     print('I am x') 
c = C() 
print(c.x) 

在上面的代碼中的打印語句顯示CX作爲一個方法,不分配給111因此,數據屬性,該代碼表示​​數據屬性不一定覆蓋方法具有相同名稱的屬性和文檔是錯誤。任何人都可以證實我的發現

P.S.我嘗試了Python 3.5和Python 2.7中的代碼,並獲得了相同的結果。

+2

變量可以遮蔽其他變量...方法和屬性與類和函數都 –

回答

3

我想教程是不幸(因爲含糊)措詞和由

[d] ATA屬性重寫方法具有相同名稱

它實際上指「數據屬性重寫先前分配的屬性/定義的同名方法屬性,反之亦然:方法屬性覆蓋以前分配/定義的同名數據屬性。「

「Duh」,你可能會認爲「數據屬性也覆蓋了先前分配的數據屬性的同名,那麼有什麼大不了的,爲什麼還要提到?賦值和重新賦值(在引用的教程中稱爲「覆蓋」)與變量(無論是否稱爲「屬性」)完全是命令式編程語言的原型特徵之一。

好,讓我給你介紹

命名空間

Python類的命名空間。那麼本教程可能試圖告訴我們的是,數據屬性方法屬性之內的一個類共享一個名稱空間。

不過,對於不同類別的屬性,情況並非如此。如果一個類繼承自另一個類,它可以訪問其父類的名稱。如果名稱在繼承類中用於方法定義或數據分配,則父類會保留原始值。在孩子階級,他們只是暫時被遮蔽。如果從子類中刪除的名字,它也將再次提供接入到同一個名字的父母的屬性:

class A: 
     x = 111 

class B1(A): 
     x = 123 # Shadows A.x 

assert B1.x == 123 

del B1.x   # But after removing B1's own x attribute ... 
assert B1.x == 111 # ... B1.x is just an alias to A.x ! 


# Shadowing can happen at any time: 

class B2(A): 
     pass 

assert B2.x == A.x == 111 

B2.x = 5 # shadowing attributes can also be added after the class definition 

assert B2.x == 5 
assert A.x == 111 

del B2.x 
assert B2.x == A.x == 111 

對比這與重新定義又名重新分配(或「重寫」的教程調用它):

class C: 
     x = 555 
     def x(self): 
       print('I am x') 

C().x() # outputs "I am x" 

del C.x 
print(C.x) # AttributeError: 'C' object has no attribute 'x' 

方法C.x()暫時沒影子數據屬性C.x。它取代了它,所以當我們刪除該方法時,xC內完全丟失,而不是在該名稱下重新顯示的數據屬性。

多個命名空間

實例化增加了對陰影另一個命名空間,因此另一個機會:

a = A() 
assert a.x == 111 # instance namespace includes class namespace 

a.x = 1000 
assert a.x == 1000 
assert A.x == 111 # class attribute unchanged 

del a.x 
assert a.x == 111 # sees A.x again 

事實上,所有的Python(嵌套)命名空間工作方式:封裝,模塊,類,函數和方法,實例對象,內部類,嵌套函數...

當讀取變量時,命名空間層次結構將自下而上地走到名稱被找到。 (這裏的意思是找到變量名稱所綁定的值(對象,函數/方法或內置),如果該值是可變的,則也可以用於更改該值。)

On另一方面,在設置(定義或重新定義)變量時,將使用當前名稱空間的名稱:如果名稱已經存在於該名稱空間中(而不是僅從其他名稱空間包含)新創建的名稱,如果它以前不存在。

+1

也有覆蓋/陰影可能發生的另一種方法:方法定義在類字典('OBJ .__類__.__ dict__')結束,而實例變量在實例字典('OBJ .__ dict__')結束了。屬性查找發生在實例字典第一,所以它可能陰影的方法具有相同的名稱,即使該方法仍存在的類字典(沒有實際的重新分配)。 –

+1

@LukasGraf好點。我已經添加了另一節。 –

+0

感謝您非常明確和廣泛的答案。 – candleindark

3

屬性覆蓋方法,反之亦然。經驗法則是,後者覆蓋前者。所以,如果你

class C: 
    x = 111 
    def x(self): 
     print('I am x') 
    x = 112 

c = C() 
print(c.x) 

你會得到

112 
+0

這是否意味着你同意,官方文檔是錯在這個問題上真的只是變量? – candleindark

+1

@candleindark文檔中的句子至少是非常具有誤導性的。就像科斯塔斯指出的那樣,後來的任務重寫前者。並且*通常是*,數據屬性(實例變量)首先在'__init __()'中被賦值,這就是爲什麼它們會比解析類聲明時分配的方法定義分配的原因。在您的例子中,你正在使用** **類級別屬性,這就是爲什麼「平時」不成立。 –

-1

你失蹤x的第二個定義,這就是爲什麼它似乎是官方文檔是錯誤的。

+1

你是什麼意思的第二個定義的X? – candleindark