2008-09-17 18 views
18

例如:爲什麼不是字典和列表在Python繼承了「len個」功能

a_list = [1, 2, 3] 
a_list.len() # doesn't work 
len(a_list) # works 

Python的是(非常)爲主,我不明白爲什麼「len個」功能是不是對象由對象繼承。 加上我一直嘗試錯誤的解決方案,因爲它對我來說似乎是合乎邏輯的

+0

函數不會被繼承。方法是。你想繼承哪個對象的`len`方法? – tzot 2008-09-17 15:55:29

+0

這是不相關的,因爲len只是調用__len__方法,所以相同的繼承問題仍然適用。 – 2008-09-18 03:32:23

+5

@Eli你的意思是`__len__`方法 - SO將雙下劃線解釋爲粗體。 =) – MatrixFrog 2010-02-14 21:58:43

回答

40

圭多的解釋是here

所有的

首先,我選擇了x.len()爲HCI原因LEN(X)(DEF __len __()來得更高版本)。實際上有兩個交織在一起的原因,其中有兩個交織在一起的原因,其中兩個HCI:

(a)對於某些操作,前綴符號讀取比po​​stfix更好 - prefix(和infix!)操作在數學中有着悠久的傳統,數學家思考一個問題。將我們用x *(a + b)重寫一個公式的簡單方法與使用原始OO表示法執行相同操作的笨拙相比較,可以輕鬆將其重寫爲x a + x b。 (b)當我閱讀說len(x)的代碼時,我知道它是要求一些東西的長度。這告訴我兩件事情:結果是一個整數,參數是某種容器。相反,當我讀取x.len()時,我必須已經知道x是某種實現接口或從具有標準len()的類繼承的容器。當一個沒有實現映射的類有get()或keys()方法,或者非文件有write()方法時,見證我們偶爾會遇到的困惑。

用另一種方式說同樣的事情,我將'len'視爲內置操作。我不想失去那個。/.../

2

也許您在尋找__len__。如果該方法存在,則len(a)將其稱爲:

>>> class Spam: 
... def __len__(self): return 3 
... 
>>> s = Spam() 
>>> len(s) 
3 
10

它只是不是。

你可以,但是,這樣做:

>>> [1,2,3].__len__() 

3 

添加__len__()方法一類是什麼使len()神奇的工作。

2

嗯,實際上是一個長的方法,它只是隱藏:

>>> a_list = [1, 2, 3] 
>>> a_list.__len__() 
3 

的LEN()內置函數似乎只是爲了給隱藏len個調用的包裝()對象的方法。

不知道他們爲什麼決定以這種方式實施這些事情。

11

簡短的回答:1)向後兼容性和2)沒有足夠的差異,它真的很重要。有關更詳細的解釋,請繼續閱讀。

這種操作的慣用Python方法是不打算直接調用的特殊方法。例如,要使x + y適用於您自己的班級,請編寫__add__方法。要確保int(spam)正確地轉換您的自定義類,請編寫__int__方法。爲確保len(foo)能夠做出明智的決定,請編寫__len__方法。

這就是Python一直以來的情況,我認爲它對於某些事情很有意義。特別是,這似乎是實現運算符重載的明智方式。至於其他,不同的語言不同意;在Ruby中,你可以通過直接調用spam.to_i而不是說int(spam)來將某些東西轉換爲整數。

你說得對,Python是一種極其面向對象的語言,不得不調用對象的外部函數來獲得它的長度似乎很奇怪。另一方面,len(silly_walks)沒有比silly_walks.len()更繁重,而Guido曾表示他實際上更喜歡它(http://mail.python.org/pipermail/python-3000/2006-November/004643.html)。

5

這種方式更適合於其他語言。 python中的約定是,您將特殊的方法添加到對象以使它們具有某些功能(而不是例如從特定基類派生)。例如,一個目的是

  • 可調用,如果它有一個__call__方法
  • 迭代,如果它有一個__iter__方法,
  • 支持具有[如果它具有__getitem____setitem__]的訪問。
  • ...

其中一種特殊的方法是__len__這使得它有len()訪問的長度。