Python erlaubte schon in den ersten Versionen, Objekte miteinander zu vergleichen. Um zu beschreiben, was "größer" oder "gleich" für Ihre Objekte bedeutet, wurden spezielle Vergleichsmethoden (eq, ne, lt, le, gt, ge) erstellt. Mit der Einführung von PEP 207 (Python 2.1+) wurde ein einheitliches Vergleichsprotokoll implementiert, damit Programmierer das Verhalten beim Vergleichen explizit steuern können.
Standardtypen (int, str) werden "nach Wert" verglichen, während benutzerdefinierte Klassen standardmäßig "nach Identität" (is) verglichen werden. Wenn man die magischen Vergleichsmethoden nicht implementiert oder falsch implementiert, führt der Vergleich von Objekten zu unerwartetem Verhalten bei der Arbeit mit Sammlungen, Sortierung, Verwendung von set und dict, und kann manchmal zu Typfehlern führen.
Es ist notwendig, die Vergleichsmethoden in Ihrer Klasse explizit zu definieren. Am häufigsten implementiert man eq (Gleichheit) und lt (kleiner), die anderen Methoden können automatisch mit dem Dekorator functools.total_ordering erhalten werden.
Codebeispiel:
from functools import total_ordering @total_ordering class Point: def __init__(self, x, y): self.x = x self.y = y def __eq__(self, other): if not isinstance(other, Point): return NotImplemented return self.x == other.x and self.y == other.y def __lt__(self, other): if not isinstance(other, Point): return NotImplemented return (self.x, self.y) < (other.x, other.y) # Verwendung: p1 = Point(1, 2) p2 = Point(1, 3) print(p1 < p2) # True print(p1 == p2) # False
Hauptmerkmale:
Kann man nur eine Vergleichsmethode (eq oder lt) implementieren, und alles wird funktionieren?
Nein. Wenn Sie nur eq implementieren, stellen Sie einen korrekten Vergleich auf Gleichheit sicher, aber die Operatoren <, >, <=, >= verhalten sich standardmäßig (in der Regel durch Vergleich von Objektidentitäten). Für das vollständige Verhalten sollten Sie ein ausreichendes Set von Methoden implementieren oder functools.total_ordering verwenden.
Warum gibt es compare(x, y) nicht in Python, wie in anderen Sprachen?
Python hat die Idee von speziellen "magischen" Methoden für jeden Operator übernommen, und die Funktion cmp wurde mit Python 3 entfernt. Für den allgemeinen Vergleich von Objekten werden die rich comparison Methoden (lt, eq usw.) verwendet, und für die Sortierung — der Parameter key in den Funktionen sort/sorted.
Was passiert, wenn man ein Objekt mit einem Typ vergleicht, für den die erforderliche Methode nicht implementiert ist?
Wenn in eq oder anderen Methoden NotImplemented bei nicht unterstützten Typen zurückgegeben wird, versucht Python automatisch, die umgekehrte Methode beim zweiten Operand zu verwenden, oder gibt False zurück. Wenn man diesen Fall nicht behandelt, kann es zu TypeError oder völlig unerwartetem Verhalten kommen.
Codebeispiel:
class Foo: def __eq__(self, other): return NotImplemented class Bar: pass print(Foo() == Bar()) # False (versucht über Bar.__eq__)
Ein Entwickler erstellte die Klasse User und implementierte nur eq ohne hash, sodass Benutzer anhand ihrer E-Mail-Adresse als gleich betrachtet werden. Später versuchte er, User-Objekte in einem set oder als Schlüssel in einem Wörterbuch zu verwenden.
Vorteile:
Nachteile:
Ein Programmierer verwendet @total_ordering und implementiert eq und lt mit Typprüfung und fügt hash hinzu, wenn die Klasse unveränderbar ist. Objekte werden korrekt verglichen, sortiert und funktionieren als Schlüssel in einem Wörterbuch.
Vorteile:
Nachteile: