2017-02-16 63 views
3

我注意到list.remove奇怪的行爲,至少不能通過C源代碼解釋(至少我)。奇怪的行爲list.remove與任意類 - 比較對象

考慮這個類:

class A: 
    def __init__(self, n1, n2): 
     self.n1 = n1 
     self.n2 = n2 

    def __eq__(self, other): 
     print('in eq') 
     return vars(self) == vars(other) 

以下代碼:

a1 = A(1, 2) 
a2 = A(1, 2) 
li = [a1, a2] 
li.remove(a1) 

我會期待它輸出in eq但它什麼也不輸出,這意味着A.__eq__不會被調用。

無論這個

a1 = A(1, 2) 
a2 = A(2, 3) 
li = [a1, a2] 
li.remove(a1) 
li.remove(a2) 

觸發器A.__eq__通話。

與同一個對象最終調用A.__eq__調用remove兩次,但(奇怪的是)只有一次:

a1 = A(1, 2) 
a2 = A(1, 2) 
li = [a1, a2] 
li.remove(a1) 
li.remove(a1) 
# 'in eq' 
  1. 爲什麼叫remove一次不叫A.__eq__remove如何知道它發現要刪除的對象? Python實現使用內存地址進行比較似乎很奇怪,即使我們覆蓋__eq__

  2. 爲什麼與同一個對象調用A.__eq__調用remove兩次,爲什麼只有一次?

回答

1

Remove方法使用is第一它使用==,即__eq__之前。因此,如果找到要刪除的對象is,則__eq__不會被調用。僅當它找不到is的對象時,纔會調用__eq__。因此,當第二次嘗試刪除對象時,它會刪除相同的對象。在這種情況下,a2。現在li是空的:

>>> li.remove(a1) 
>>> li.remove(a1) 
>>> li 
[] 

當你調用li.remove(a1)第三次,你會等一個ValueError

+0

正如我懷疑。我懷疑是否有一個很好的歷史原因,即使我們重寫'__eq__','remove'也會首先使用'is'。我相信獲得的表現是可以忽略的。 – DeepSpace

+0

如果您有比較大的列表來比較'is'可以比單獨比較每個列表元素快得多。 –