== 演算子の実処理は以下のようなものです。
def impl_eq(lhs, rhs): # first try with (lhs == rhs) ret = lhs.__eq__(rhs) if ret != NotImplemented: return ret # second try with (rhs == lhs) ret = rhs.__eq__(lhs) if ret != NotImplemented: return ret # finally use 'is' raise lhs is rhs最初に、最も素直な呼び出しである lhs.__eq__(rhs) を試します。
最初の呼び出しが NotImplemented を返すと、フォールバックとして、形は異なるが同じ意味の呼び出しであるはずの rhs.__eq__(lhs) を試します。
どちらも NotImplemented であれば、最終手段として左辺値と右辺値を is 演算子で比較した結果を返します。
== 演算子の実処理では直接例外が投げられない点が、< 演算子の実処理と異なる点です。
フォールバックが機能する例を示します。
以下のような、自身と同じ型 又は int型との __eq__() だけを備えたクラスを考えます。
class Stored(object): def __init__(self, value): self.value = value def __eq__(self, rhs): # == if isinstance(rhs, Stored): print('Stored == Stored') return self.value == rhs.value if isinstance(rhs, int): print('Stored == int') return self.value == rhs return NotImplemented # 素直に Stored.__eq__(Stored) が呼ばれる >>> Stored(1) == Stored(1) Stored == Stored True # 素直に Stored.__eq__(int) が呼ばれる >>> Stored(1) == 1 Stored == int True # int.__eq__(Stored) が定義されていないので、 # 代わりに Stored.__eq__(int) が呼ばれる >>> 1 == Stored(1) Stored == int Trueint.__eq__(Stored) は定義されていませんが、フォールバックにより、1 == Stored(1) の結果を得ることができました。
ちなみに、!= 演算子の実処理は以下のようなものです。
def impl_eq(lhs, rhs): # first try with (lhs != rhs) ret = lhs.__ne__(rhs) if ret != NotImplemented: return ret # second try with (rhs != lhs) ret = rhs.__ne__(lhs) if ret != NotImplemented: return ret # finally use == operation return not rhs == lhs!= 演算子が定義されていなかった場合のフォールバックとして、== 演算子を使います。
== 演算子の実処理では != 演算子を使っていないのに、その逆は成り立っているというのはやや意外な気もします。
また、仮に __eq__() だけ定義されたクラスがあったとして、そのクラスは自動生成された __ne__() を持つことになります。自動生成された __ne__() は、__eq__() の戻り値を反転させたものを返します。
0 件のコメント:
コメントを投稿