2017-02-16 5 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は、どのようにオブジェクトを削除することがわかっていますか? __eq__をオーバーライドしても、比較のためにPythonの実装でメモリアドレスを使用するのは奇妙に思えます。

  2. 同じオブジェクトで二回removeを呼び出すのはなぜ

    A.__eq__を呼び出すで、なぜ一度だけ?それは、すなわち__eq__==を使用する前に

答えて

1

削除方法は、第1 isを使用します。だから、isで削除したいオブジェクトが見つかった場合、__eq__は呼び出されません。 isでオブジェクトを見つけることができない場合にのみ、__eq__を呼び出します。したがって、2回目にオブジェクトを削除しようとすると、等しいオブジェクトが削除されます。この場合、a2。今liは空です:

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

あなたは私がValueError

+0

疑わられるように三度目li.remove(a1)を呼び出すとき。私たちが '__eq__'を上書きしたとしても、最初に' remove'を使うのは良い歴史的理由があるのだろうかと思います。私は得られたパフォーマンスが無視できると信じています。 – DeepSpace

+0

'' is'を比較する大きなリストがある場合、各リスト要素を個別に比較するよりもずっと速くなります。 –