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 Noneverwenden is(für weitere Informationen zum Ende der Antwort springen).
Du hast gemacht
None.__eq__('a')
# NotImplemented
Welche Renditen NotImplementedseit 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. 1und '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
Falsewerden 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 NotImplementedes 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 NotImplementedtruthy ist, aber es wäre eine andere Geschichte die Klasse eine definierte hatte gewesen __bool__oder __len__Verfahren , dass zurückgegeben Falseoder 0sind.
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
Noneist ein spezielles Objekt, und zu jedem Zeitpunkt ist nur 1 Version im Speicher vorhanden. IOW, es ist der einzige Singleton der NoneTypeKlasse (aber dasselbe Objekt kann eine beliebige Anzahl von Referenzen haben). Die PEP8-Richtlinien machen dies deutlich:
Vergleiche mit Singletons wie Nonesollten immer mit isoder
is notniemals mit den Gleichheitsoperatoren durchgeführt werden.
Zusammenfassend ist für Singletons wie Noneeine Referenzprüfung mit isbesser geeignet, obwohl beide ==und gut isfunktionieren.