回答:
これは、__dunder__メソッドが同等の演算子の適切な置換ではない場合が多いため、メソッドを直接使用しない理由の良い例です。==等価比較には代わりに演算子を使用する必要があります。または、この特殊なケースでは、を確認するときNoneに使用しますis(詳細については、回答の最後までスキップしてください)。
あなたがやった
None.__eq__('a')
# NotImplemented
NotImplemented比較される型が異なるため、どちらが返されますか。以下のような、異なるタイプの2つのオブジェクトが、この方法で比較されている別の例を考える1と'a'。行うこと(1).__eq__('a')も正しくなく、戻りNotImplementedます。これら2つの値が等しいかどうかを比較する正しい方法は、
1 == 'a'
# False
ここで何が起こるか
(1).__eq__('a')が返されますNotImplemented。これは、操作がサポートされていないことを示しているため、'a'.__eq__(1)が呼び出され、これも同じを返しますNotImplemented。そう、False返されます。これがどのように発生するかを説明するためにいくつかのカスタムクラスを使用した素敵な小さなMCVEです。
class A:
def __eq__(self, other):
print('A.__eq__')
return NotImplemented
class B:
def __eq__(self, other):
print('B.__eq__')
return NotImplemented
class C:
def __eq__(self, other):
print('C.__eq__')
return True
a = A()
b = B()
c = C()
print(a == b)
# A.__eq__
# B.__eq__
# False
print(a == c)
# A.__eq__
# C.__eq__
# True
print(c == a)
# C.__eq__
# True
もちろん、それは操作がtrueを返す理由を説明していません。これは、NotImplementedが実際には真実の値だからです。
bool(None.__eq__("a"))
# True
と同じ、
bool(NotImplemented)
# True
どの値が真偽であると見なされるかについての詳細は、真理値テストのドキュメントセクションとこの回答を参照してください。ここでNotImplemented真実であることは注目に値しますが、クラスが、またはをそれぞれ返す、__bool__または__len__メソッドを定義した場合は、別の話になります。False0
==演算子と同等の機能が必要な場合は、次を使用しますoperator.eq。
import operator
operator.eq(1, 'a')
# False
ただし、前述したように、この特定のシナリオでは、次のことを確認しNoneますis。
var = 'a'
var is None
# False
var2 = None
var2 is None
# True
これに相当する機能は次を使用していoperator.is_ます:
operator.is_(var2, None)
# True
Noneは特別なオブジェクトであり、いつでもメモリに存在するバージョンは1つだけです。IOW、それはNoneTypeクラスの唯一のシングルトンです(ただし、同じオブジェクトは任意の数の参照を持つことができます)。PEP8ガイドラインは、これは明示的に行います。
のようなシングルトンとの比較
Noneは、常にisまたはを 使用して行う必要がありますis not。等価演算子は使用しないでください。
要約すると、のようなシングルトンのためにNone、と参照チェックはis両方が、より適切である==とisうまく動作します。
あなたが見ている結果は、
None.__eq__("a") # evaluates to NotImplemented
はに評価されNotImplemented、NotImplementedの真理値は次のように文書化されますTrue。
https://docs.python.org/3/library/constants.html
(例えば、バイナリ特別なメソッドによって返さなければならない特別な値
__eq__()、__lt__()、__add__()、__rsub__()、など)の動作は他のタイプに対して実装されていないことを示すために。インプレースバイナリ特殊な方法(例えばによって返されることがあり__imul__()、__iand__()同じ目的のために、など)。その真理値は真実です。
__eq()__だけを使用するのではなく、手動でメソッドを呼び出す場合は、メソッド==が返す可能性とNotImplementedその真の値がtrue である可能性に対処する準備をする必要があります。
それはNotImplementedええを返します:
>>> None.__eq__('a')
NotImplemented
>>>
しかし、これを見ると:
>>> bool(NotImplemented)
True
>>>
NotImplementedtruthy値が、実際にそれを返す理由のようにb、あるものTrueで通過し、何もFalseないでしょう。
それがTrueであるかどうかを確認する必要があるため、次のように、より疑わしいものにします。
>>> NotImplemented == True
False
>>>
だからあなたはそうするでしょう:
>>> if None.__eq__('a') == True:
print('b')
>>>
ご覧のとおり、何も返されません。