インスタンスの同値を見る方法を考えてみた

python2.7にて試してみた。3.xではこの方法は使えないので注意。
勢いに任せて書いてみたが、もっと短くできそうな気もする。
こういうクラスを考えてみる

class Aa(object):
    def __init__(self, a, b):
        self.id = a
        self.name = b

e = Aa(1, "akebono")
r = Aa(2, "konishiki")
t = Aa(1, "akebono")

という時に、 eと、rは等しいか?、当然、等しくない。
では、eとt は「等しい」のか?確かめてみるとこうなる

>>>e == r
False
>>>e == t
False
>>>e.id == t.id
True
>>>e.name == t.name
True

e とrは別々のオブジェクトで、たまたま同じプロパティ(pythonでは広くアトリビュートという)を持っているに過ぎない。別々のオブジェクトだから「等しくない」。それは、オブジェクトを見てみればわかる。

>>> e
<__main__.Aa object at 0x1004cbdd0>
>>> t
<__main__.Aa object at 0x1004cbe10>
>>> 

とはいえ、たくさんのインスタンスを作った時に比較できないのは不便なので、プロパティが同じ物を比較する方法を考えてみた。要は、javaでいうequalsの実装。

class Eq(object):
    def equals(self, other):
        b = []
        for i in dir(self):
            if str(type(getattr(self, i))) != "<type 'instancemethod'>" and i.find("__") < 0:
                if getattr(self, i) == getattr(other, i):
                    b.append(True)
                else:
                    b.append(False)
        if len(b) == b.count(True):
            return True
        else:
            return False

class Aa(Eq):
    def __init__(self, a, b):
        self.id = a
        self.name = b
    

e = Aa(1, "akebono")
r = Aa(2, "konishiki")
t = Aa(1, "akebono")

# 確認してみると
>>> e.equals(r)
False
>>> e.equals(t)
True
>>> e.equals(e)
True
>>> e == t
False

__のついたプロパティは比較から外している。
objectを継承しているので、__eq__をこの、equalsでオーバーライドすると、 == で比較することもできる。