目的
pythonにおいてオブジェクトの同値判定の仕組みを知った上で自分で定義した同値判定を利用できるようにする
obj1 == obj2
および obj1!=obj2
での判定の仕組みについて
環境
python : 3.5.1, 2.7.10
pythonの組み込み関数での同値判定
class Foo(object):
def __init__(self, name, age):
self.name = name
self.age = age
上記の通り、Fooクラスを定義した上で以下のようにfoo1とfoo2のインスタンスを作成して、
同値判定やリストの存在の有無の判定を行うと、同じインスタンスではTrueになるが、メンバ変数の値が同じでインスタンスが異なる場合はFalseになる。
foo1 = Foo("foo", 24)
foo2 = Foo("foo", 24)
print(foo1 == foo1) # -> True
print(foo1 == foo2) # -> False
print(foo1 in [ foo1 ]) # -> True
print(foo1 in [ foo2 ]) # -> False
print(foo1 != foo1) # -> False
print(foo1 != foo2) #-> True
自作する場合
pythonの==
やobj in objlist
で同値判定を行う際には、
obj.__eq__
メソッドが呼び出される
一方、!=
には、obj.__ne__
が 呼び出される
ただし、obj.__eq__
を定義すれば、3.5.1(3系全部?)ではobj.__ne__
はその逆を返してくれるのでobj.__eq__
のみをオーバライドすればよい
2.7.10では、__ne__
も定義してあげないと、obj.__ne__
の結果はオーバライドしたobj.__eq__
の逆の値を返してくれない
2系と3系で統一したい場合は、__ne__
を定義しておくことをお勧めします。
ただし、__eq__
のときはまず始めに比較対象が同じクラスかどうかの判定するメソッドisinstance(obj, CLASSNAME)
を呼び出さないといけないことに注意
メンバ変数のname
とage
が同じであれば、同じとみなす場合、以下のように定義する
class Bar(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __eq__(self, obj):
if isinstance(obj, Bar):
return self.name == obj.name and self.age == obj.age
else:
return False
# 2.7.10(おそらく2.7系全部)では以下も必要
def __ne__(self, obj):
return not self.__eq__(obj)
上記のようにBarクラスを定義し、bar1, bar2, bar3 のインスタンスを以下のように作成して同値判定等の結果を見ると次のようになる
bar1 = Bar("bar", 24)
bar2 = Bar("bar", 24)
bar3 = Bar("foo", 24)
print(bar1 == bar1) # -> True
print(bar1 == bar2) # -> True
print(bar1 == bar3) # -> False
print(bar1 in [ bar1 ]) # -> True
print(bar2 in [ bar1 ]) # -> True
print(bar3 in [ bar1 ]) # -> False
print(bar1 != bar1) # -> False
print(bar1 != bar2) # -> False 2.7.10では__ne__を定義してないとTrueになる
print(bar1 != bar3) # -> True