回答:
これは、__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__
メソッドを定義した場合は、別の話になります。False
0
==
演算子と同等の機能が必要な場合は、次を使用します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
>>>
NotImplemented
truthy値が、実際にそれを返す理由のようにb
、あるものTrue
で通過し、何もFalse
ないでしょう。
それがTrue
であるかどうかを確認する必要があるため、次のように、より疑わしいものにします。
>>> NotImplemented == True
False
>>>
だからあなたはそうするでしょう:
>>> if None.__eq__('a') == True:
print('b')
>>>
ご覧のとおり、何も返されません。