Python 3.7 で次のステートメントを実行すると、(私のテストでは) 次のように出力されますb
。
if None.__eq__("a"):
print("b")
ただし、None.__eq__("a")
は と評価されますNotImplemented
。
当然、"a".__eq__("a")
は に評価されTrue
、"b".__eq__("a")
は に評価されますFalse
。
最初に関数の戻り値をテストしているときにこれを発見しましたが、2 番目のケースでは何も返さなかったため、関数は を返しましたNone
。
何が起きてる?
ベストアンサー1
__dunder__
これは、メソッドを直接使用すべきではない理由を示す良い例です。==
メソッドは、同等の演算子の適切な代替ではないことが非常に多いためです。等価比較には代わりに演算子を使用する必要があります。または、この特殊なケースでは、 をチェックするときにNone
を使用しますis
(詳細については、回答の最後までスキップしてください)。
完了しました
None.__eq__('a')
# NotImplemented
比較する型が異なるため、が返されます。とNotImplemented
のように、異なる型の 2 つのオブジェクトをこのように比較する別の例を考えてみましょう。 を実行することも正しくなく、 が返されます。これら 2 つの値が等しいかどうかを比較する正しい方法は、次のようになります。1
'a'
(1).__eq__('a')
NotImplemented
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つのバージョンしか存在しません。つまり、それはクラスの唯一のシングルトンですNoneType
(ただし、同じオブジェクトに任意の数の参照がある場合があります)。PEP8ガイドラインこれを明確にします:
のようなシングルトンとの比較は、常にまたは を
None
使用して行う必要があり、等価演算子は使用しないでください。is
is not
要約すると、 のようなシングルトンの場合、 と の両方でも問題なく動作しますが、None
を使用した参照チェックの方is
が適切です。==
is