web-dev-qa-db-ja.com

Pythonの属性によってオブジェクトインスタンスが等しいかどうかを比較します

クラスMyClassがあり、これには2つのメンバー変数foobarが含まれています。

class MyClass:
    def __init__(self, foo, bar):
        self.foo = foo
        self.bar = bar

このクラスのインスタンスは2つあり、それぞれfoobarの値が同じです。

x = MyClass('foo', 'bar')
y = MyClass('foo', 'bar')

ただし、それらを同等かどうか比較すると、PythonはFalseを返します。

>>> x == y
False

どうすればpythonこれら2つのオブジェクトを等しいと見なすことができますか?

203

メソッドを実装する必要があります __eq__

class MyClass:
    def __init__(self, foo, bar):
        self.foo = foo
        self.bar = bar

    def __eq__(self, other): 
        if not isinstance(other, MyClass):
            # don't attempt to compare against unrelated types
            return NotImplemented

        return self.foo == other.foo and self.bar == other.bar

次のように出力されます:

>>> x == y
True

__eq__を実装すると、クラスのインスタンスが自動的にハッシュ不可になります。つまり、セットや辞書に格納することはできません。不変の型をモデル化していない場合(つまり、属性fooおよびbarがオブジェクトの存続期間内に値を変更する可能性がある場合)は、インスタンスをハッシュ不可のままにすることをお勧めします。

不変型をモデル化する場合は、datamodelフック __hash__ も実装する必要があります。

class MyClass:
    ...

    def __hash__(self):
        # necessary for instances to behave sanely in dicts and sets.
        return hash((self.foo, self.bar))

__dict__をループして値を比較するというアイデアのような一般的な解決策はお勧めできません-__dict__には比較できないまたはハッシュできないタイプが含まれている可能性があるため、真に一般的ではありません。

N.B .: Python 3の前に、__cmp__の代わりに __eq__ を使用する必要があることに注意してください。 Python 2人のユーザーは、 __ne__ を実装することもできます。これは、不平等に対する適切なデフォルト動作(つまり、等式結果の反転)がPythonで自動的に作成されないためです2。

290
e-satis

オブジェクトの リッチ比較演算子 をオーバーライドします。

class MyClass:
 def __lt__(self, other):
      # return comparison
 def __le__(self, other):
      # return comparison
 def __eq__(self, other):
      # return comparison
 def __ne__(self, other):
      # return comparison
 def __gt__(self, other):
      # return comparison
 def __ge__(self, other):
      # return comparison

このような:

    def __eq__(self, other):
        return self._id == other._id
44
Christopher

クラスに__eq__メソッドを実装します。このようなもの:

def __eq__(self, other):
    return self.path == other.path and self.title == other.title

編集:オブジェクトに等しいインスタンスディクショナリがある場合にのみ、オブジェクトを同等に比較する場合:

def __eq__(self, other):
    return self.__dict__ == other.__dict__
5
Kiv

要約として:

  1. python <= 2.0を実行する場合を除き、__eq__ではなく__cmp__を実装することをお勧めします(2.1で__eq__が追加されました)
  2. __ne__も実装することを忘れないでください(非常に特殊な場合を除き、return not self.__eq__(other)またはreturn not self == otherのようなものでなければなりません)
  3. 比較する各カスタムクラスに演算子を実装する必要があることを忘れないでください(以下の例を参照)。
  4. Noneにできるオブジェクトと比較する場合は、実装する必要があります。インタプリタは推測できません...(以下の例を参照)

    class B(object):
      def __init__(self):
        self.name = "toto"
      def __eq__(self, other):
        if other is None:
          return False
        return self.name == other.name
    
    class A(object):
      def __init__(self):
        self.toto = "titi"
        self.b_inst = B()
      def __eq__(self, other):
        if other is None:
          return False
        return (self.toto, self.b_inst) == (other.toto, other.b_inst)
    
4
fievel

オブジェクトのインスタンスを比較するとき、 __cmp__ 関数が呼び出されます。

==演算子がデフォルトで機能しない場合、オブジェクトの__cmp__関数をいつでも再定義できます。

編集:

指摘されているように、__cmp__関数は3.0から非推奨になりました。代わりに “リッチ比較” メソッドを使用する必要があります。

2
Silfverstrom

属性ごとの比較を取得し、失敗するかどうか、どこで失敗するかを確認する場合は、次のリスト内包表記を使用できます。

[i for i,j in 
 Zip([getattr(committed_vans_events[0][0].request, attr) 
      for attr in dir(committed_vans_events[0][0].request)],
     [getattr(self.vans_states[0].onboard_passengers[0], attr) 
      for attr in dir(self.vans_states[0].onboard_passengers[0])]) 
 if not i==j]

ここでの追加の利点は、PyCharmでデバッグするときに1行圧縮して「式の評価」ウィンドウに入力できることです。

0
DalyaG