Dies ist ein gutes Beispiel dafür, warum die __dunder__
Methoden nicht direkt verwendet werden sollten, da sie häufig keinen geeigneten Ersatz für ihre äquivalenten Operatoren darstellen. Sie sollten ==
stattdessen den Operator für Gleichheitsvergleiche verwenden oder in diesem speziellen Fall bei der Suche nach None
verwenden is
(für weitere Informationen zum Ende der Antwort springen).
Du hast gemacht
None.__eq__('a')
# NotImplemented
Welche Renditen NotImplemented
seit dem Vergleich der Typen unterschiedlich sind. Stellen Sie sich ein anderes Beispiel vor, in dem zwei Objekte mit unterschiedlichen Typen auf diese Weise verglichen werden, z. B. 1
und 'a'
. Das Tun (1).__eq__('a')
ist auch nicht korrekt und wird zurückkehren NotImplemented
. Der richtige Weg, um diese beiden Werte auf Gleichheit zu vergleichen, wäre
1 == 'a'
# False
Was hier passiert ist
- Zunächst
(1).__eq__('a')
wird versucht, was zurückkehrt NotImplemented
. Dies zeigt an, dass der Vorgang nicht unterstützt wird
'a'.__eq__(1)
heißt, was auch das gleiche zurückgibt NotImplemented
. So,
- Die Objekte werden so behandelt, als wären sie nicht identisch, und
False
werden zurückgegeben.
Hier ist eine nette kleine MCVE, die einige benutzerdefinierte Klassen verwendet, um zu veranschaulichen, wie dies geschieht:
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
Das erklärt natürlich nicht, warum die Operation true zurückgibt. Dies liegt daran, dass NotImplemented
es sich tatsächlich um einen wahrheitsgemäßen Wert handelt:
bool(None.__eq__("a"))
# True
Gleich wie,
bool(NotImplemented)
# True
Weitere Informationen darüber, welche Werte als wahr und falsch angesehen werden, finden Sie im Abschnitt Dokumente zum Testen von Wahrheitswerten sowie in dieser Antwort . Es ist erwähnenswert , dass NotImplemented
truthy ist, aber es wäre eine andere Geschichte die Klasse eine definierte hatte gewesen __bool__
oder __len__
Verfahren , dass zurückgegeben False
oder 0
sind.
Wenn Sie das funktionale Äquivalent des ==
Operators wünschen , verwenden Sie operator.eq
:
import operator
operator.eq(1, 'a')
# False
Wie bereits erwähnt, verwenden Sie für dieses spezielle Szenario , in dem Sie suchen None
, Folgendes is
:
var = 'a'
var is None
# False
var2 = None
var2 is None
# True
Das funktionale Äquivalent dazu ist operator.is_
:
operator.is_(var2, None)
# True
None
ist ein spezielles Objekt, und zu jedem Zeitpunkt ist nur 1 Version im Speicher vorhanden. IOW, es ist der einzige Singleton der NoneType
Klasse (aber dasselbe Objekt kann eine beliebige Anzahl von Referenzen haben). Die PEP8-Richtlinien machen dies deutlich:
Vergleiche mit Singletons wie None
sollten immer mit is
oder
is not
niemals mit den Gleichheitsoperatoren durchgeführt werden.
Zusammenfassend ist für Singletons wie None
eine Referenzprüfung mit is
besser geeignet, obwohl beide ==
und gut is
funktionieren.