Programmingミドル Python 開発者

Pythonにおける比較演算子 '==' とメソッド __eq__ の動作はどのように決まっているか? 自分のクラスの比較動作を変更するにはどうすればよいか?

Hintsage AIアシスタントで面接を突破

回答。

背景:

Pythonでは、オブジェクトを値で比較する際、演算子 '==' が使われ、内部でメソッド eq が呼び出されます。このメソッドのデフォルトの動作は、object から継承され、オブジェクトの同一性を比較します(ほとんどのクラスで)。

問題:

ユーザー定義のクラスのインスタンスを意味のある方法で比較したい場合(例えば、同じデータセットを持つ異なる Person オブジェクトが等しいとみなされる場合)、標準の動作では不十分です — 比較がどのように行われるかを明示的に定義する必要があります。

解決策:

'==' の動作を変更するには、自分のクラス内で eq メソッドをオーバーライドする必要があります。クラスがハッシュ可能である必要がある場合、hash もオーバーライドする必要があります。

コードの例:

class Person: def __init__(self, name, age): self.name = name self.age = age def __eq__(self, other): if not isinstance(other, Person): return NotImplemented return self.name == other.name and self.age == other.age p1 = Person("Ann", 25) p2 = Person("Ann", 25) print(p1 == p2) # True

主な特徴:

  • '==' は eq を呼び出します。
  • eq がないオブジェクトを比較すると、その同一性(id)が比較されます。
  • セットや辞書で正しく機能させるためには、hash も実装する必要があります。

陰謀のある質問。

異なる型のオブジェクトに対して、'==' の比較は常に対称的ですか?

必ずしもそうではありません — 最初のオブジェクトが NotImplemented を返すと、逆の比較が呼び出されます。そうでなければ、非対称になる可能性があります。

class A: def __eq__(self, other): return True class B: pass print(A() == B()) # True print(B() == A()) # False

eq を実装しない場合、同じユーザー定義クラスのオブジェクトはどう比較されますか?

同一性(メモリ内の同一性、属性の値ではなく)が比較されます。

class Foo: def __init__(self, x): self.x = x f1 = Foo(5) f2 = Foo(5) print(f1 == f2) # False

辞書のキーであるべきオブジェクトに対して eqhash なしで定義できますか?

いいえ。もし eq が変更された場合、hash も定義することが望ましく、そうしないとオブジェクトはハッシュ可能でなくなります(キーとして使用すると TypeError が発生します)。

class Foo: def __eq__(self, other): return True # hash は object から継承されますが、動作は予測不可能になります # 明示的に __hash__ を定義する方が良いです

よくあるミスとアンチパターン

  • 辞書/セットのキーが必要な場合に hash なしで eq を実装する。
  • 異なる型のオブジェクトとの比較でのミス(NotImplemented を返すべきです。False ではなく)。
  • eqhash の定義が不一致で、ハッシュ構造内での不正な動作を引き起こす。

実生活の例

ネガティブケース

ValueObject クラスの設計時に、eq のみを実装し、hash を実装し忘れました。オブジェクトを辞書のキーまたはセットの要素として使用しようとしたときに、TypeError が発生しました。

利点:

ユーザー定義の比較を迅速に導入できます。

欠点:

オブジェクトをセットや辞書で使用できない、デバッグが難しい。

ポジティブケース

別のプロジェクトでは、開発者が明示的に両方のメソッド — eqhash を実装し、「2つのオブジェクトが eq で等しいならば、ハッシュも一致する」というルールに厳密に従いました。

利点:

ハッシュ構造が正しく機能し、一貫した動作、メンテナンスが容易です。

欠点:

値が等しいオブジェクトがハッシュコンテナ内で識別できないため、柔軟性の喪失。