Stand: 2013-01-15
Spezialmethoden in Python
Operatorüberladung, Anpassung des grundlegenden Objektverhaltens, Funktionsobjekte, eigene Collections und einiges mehr wird bei Python mit Hilfe der Methoden mit den doppelten Unterstrichen erledigt. Eine Übersicht.
Inhalt
Funktionsweise von Spezialmethoden
Hauptsächlich aus historischen Gründen sieht die Objektorientierung in Python etwas anders aus, als in einigen anderen Sprachen. Um zum Beispiel die Länge von etwas zu ermitteln ruft man nicht something.len()
sondern len(something)
auf. Wenn man andere Sprachen gewohnt ist, kann das irritierend sein, es hat aber auch den Vorteil, dass die Länge bei allen Objekten gleich ermittelt wird und nicht ein Objekt eine len()
-Methode, ein anderes eine length()
- und wieder ein anderes eine size()
-Methode hat.
Aber welche Methode muss eine Klasse haben, damit len(s)
die Länge liefert? Würde man s.len()
aufrufen, wäre die Sache klar: man müsste len()
in der Klasse überschreiben, von der s
eine Instanz ist. In Python wird aber hinter den Kulissen eine sogenannte Spezialmethode aufgerufen, die nicht offensichtlich ist.
>>> class S:
def __len__(self):
return 99
>>> s = S()
>>> len(s)
99
Auch die API-Dokumentation von len(s), gibt über diesen Zusammenhang leider keine Auskunft. Um die Arbeit etwas zu erleichtern, habe ich deshalb die folgende Liste mit Spezialmethoden aufgeschrieben.
Ein wesentlicher Zweck von Spezialmethoden ist außerdem die Operatorüberladung. Beispielsweise wird x < y
durch die Methode __le__(self, other)
auf dem Objekt x
realisiert. "le" steht für den Namen des Operators "less" (kleiner).
Instanziierung
Nutzung | Spezialmethode | Erklärung |
---|---|---|
x = X() |
__new__(cls, [,...]) |
Erzeugt eine neue Instanz. Erlaubt Klassen, die von unveränderlichen Typen (wie int, str, tuple) abgleitet sind, die Instanziierung anzupassen. Anschließend wird __init__ aufgerufen. |
x = X() |
__init__(self, [,...]) |
Initialisiert das Objekt. |
Darstellung
Nutzung | Spezialmethode | Erklärung |
---|---|---|
repr(x) |
__repr__(self) |
String-Darstellung von x, die mit eval wieder in ein Objekt verwandelt werden kann: eval(repr(x)) == x |
str(x) |
__str__(self) |
für Menschen lesbare Darstellung von x |
bool(x) |
__bool__(self) |
Wahrheitswert, Objekte mit dieser Methode können in boolschen Ausdrücken verwendet werden: if x: |
bytes(x) |
__bytes__(self) |
Byte-String-Darstellung von x |
"{0}".format(x) |
__format__(self, spec) |
Bestimmt die Darstellung in formatierten Strings. |
hash(x) |
__hash__(x) |
Ermittelt den Hash-Wert, der in Dictionaries oder Sets genutzt wird. |
Funktionsobjekte
Nutzung | Spezialmethode | Erklärung |
---|---|---|
x([args ...]) |
__call__(self [,args ...]) |
Macht ein Objekt wie eine Funktion aufrufbar. |
Kontextmanager
Nutzung | Spezialmethode | Erklärung |
---|---|---|
with expression as variable: |
__enter__(self) |
Wird ausgeführt, wenn der der Code-Block betreten wird. |
with expression as variable: |
__exit__(self, exc_type, exc_value, traceback) |
Wird ausgeführt, wenn der der Code Block verlassen wird. |
Vergleiche
Nutzung | Spezialmethode | Erklärung |
---|---|---|
x < y |
__lt__(self, other) |
True, wenn x kleiner y |
x <= y |
__le__(self, other) |
True, wenn x kleiner oder gleich y |
x == y |
__eq__(self, other) |
True, wenn x gleich y |
x != y |
__ne__(self, other) |
True, wenn x ungleich y |
x >= y |
__ge__(self, other) |
True, wenn x größer oder gleich y |
x > y |
__gt__(self, other) |
True, wenn x größer y |
Wenn __eq__(self, other)
implementiert ist, wird der Ungleichheitsoperator !=
automatisch ergänzt. Zusammen mit __eq__(self, other)
sollte auch __hash__()
überschrieben werden, weil gleiche Objekte auch immer den gleichen Hash-Werte haben müssen, um in Collections, die Hash-Werte nutzen (z. B. set, dict), verwendet werden zu können. Falls die Objekte allerdings veränderlich sind, sollte __hash__()
nicht implementiert werden, weil sich der Hash-Wert eines Objekts in einer Collection sonst nachträglich ändern würde, was zu Fehlern führen würde. Siehe Dokumentation zu __hash__()
Vergleichsoperatoren können mit dem Klassendekorator @functools.total_ordering auch aus einer einzigen Vergleichsmethode abgeleitet werden.
Rechenoperationen
Nutzung | Spezialmethode | Erklärung |
---|---|---|
abs(x) |
__abs__(self) |
Betrag |
complex(x) |
__complex__(self) |
Konvertierung in eine komplexe Zahl |
float(x) |
__float__(self) |
Konvertierung in eine Gleitkommazahl |
int(x) |
__int__(self) |
Konvertierung in einen Integer |
bin(x) oder oct(x ) oder hex(x) |
__index__(self) |
??? |
+x |
__pos__(self) |
Umwandlung in einen positiven Wert |
-x |
__neg__(self) |
Umwandlung in einen negativen Wert |
round(x, digits) |
__round(self, digits) |
rundet auf die gegebene Anzahl Stellen |
x + y |
__add__(self, other) |
addiert |
x += y |
__iadd__(self, other) |
addiert und weist das Ergebnis x zu |
x - y |
__sub__(self, other) |
subtrahiert |
x -= y |
__isub__(self, other) |
subtrahiert und weist das Ergebnis x zu |
x * y |
__mul__(self, other) |
multipliziert |
x *= y |
__imul__(self, other) |
multipliziert und weist das Ergebnis x zu |
x % y |
__mod__(self, other) |
Modulo |
x %= y |
__imod__(self, other) |
Modulo, weist Ergebnis x zu |
x / y |
__truediv__(self, other) |
dividiert |
x /= y |
__itruediv(self, other) |
dividiert und weist das Ergebnis x zu |
x // y |
__floordiv__(self, other) |
teilt ganzzahlig |
x //= y |
__ifloordiv__(self, other) |
teilt ganzzahlig und weist das Ergebnis x zu |
divmod(x, y) |
__divmod__(self, other) |
teilt ganzzahlig mit Rest |
x ** y |
__pow__ |
potenziert |
x **= y |
__ipow__(self, other) |
potenziert und weist das Ergebnis x zu |
Zusätzlich gibt es noch die Methoden __radd__
, __rsub__
, __rmul__
, __rtruediv__
, __rfloordiv__
, __rmod__
, __rdivmod__
, __rpow__
, __rlshift__
, __rrshift__
, __rand__
, __rxor__
, __ror__
, die die binär-arithmetischen Operationen +, -, *, /, //, %, divmod(), pow(), **, <<, >>, &, ^, |
implementieren. Diese Methoden werden aber nur aufgerufen, wenn der linke Operand die zugehörige "normale" Methode (ohne "r" am Anfang) nicht unterstützt und die Operanden von verschiedenen Typen sind.
Binäre Operationen
Nutzung | Spezialmethode | Erklärung |
---|---|---|
x ^ y |
__xor__(self, other) |
exklusive ODER-Verknüpfung |
x ^= y |
__ixor__(self, other) |
exklusive ODER-Verknüpfung, weist Ergebnis x zu |
x & y |
__and__(self, other) |
UND-Verknüpfung |
x &= y |
__iand__(self, other) |
UND-Verknüpfung, weist Ergebnis x zu |
x | y |
__or__(self, other) |
ODER-Verknüpfung |
x |= y |
__ior__(self, other) |
ODER-Verknüpfung, weist Ergebnis x zu |
x << y |
__lshift__(self, other) |
Linksverschiebung |
x <<= y |
__ilshift__(self, other) |
Linksverschiebung, weist Ergebnis x zu |
x >> y |
__rshift__(self, other) |
Rechtsverschiebung |
x >>= y |
__irshift__(self, other) |
Rechtsverschiebung, weist Ergebnis x zu |
Operationen auf Collections
Nutzung | Spezialmethode | Erklärung |
---|---|---|
x in y |
__contains__(self, x) |
Prüft, ob ein Element enthalten ist |
del y[n] |
__delitem__(self, n) |
Löscht das n-te Element |
y[n] |
__getitem__(self, n) |
Gibt das n-te Element oder das Element mit dem Schlüssel n zurück |
y[n] = x |
__setitem__(self, n, x) |
Setzt das n-te Element oder das Element mit dem Schlüssel n auf den Wert x |
for x in y |
__iter__(self) |
Gibt einen Iterator zurück |
reversed(y) |
__reversed__(self) |
Gibt einen Rückwärts-Iterator zurück |
len(s) |
__len__(self) |
Ermittelt die Länge von s |
Beispiel: Mit diesen Methoden kann ein Dictionary geschrieben werden, das zu einem Schlüssel mehrere Werte speichert und standardmäßig den zuletzt eingefügten Wert zurückgibt. Diese Datenstruktur ist nützlich, um Werte aus HTTP-Requests zu speichern, wo ein Schlüssel mehrfach vorkommen kann.
class MultiValueDict(dict):
""" Dictionary which can contain multiple values for each key. """
def __setitem__(self, key, value):
self.setdefault(key, []).insert(0, value)
def __getitem__(self, key):
""" Returns the last inserted value for the key. """
return super(MultiValueDict, self).__getitem__(key)[0]
def get_all(self, key):
""" Returns a list with all values for the key. """
return super(MultiValueDict, self).__getitem__(key)
Genutzt werden kann es fast wie ein normales Dictionary:
>>> mv = MultiValueDict()
>>> mv["x"] = "a"
>>> mv["x"] = "b"
>>> mv["x"]
'b'
>>> mv.get_all("x")
['b', 'a']
Weitere Information
- Python-Dokumentation: Special method names
- Why does python use 'magic methods'?
- Programming in Python 3, Second Edition, Mark Summerfield, Pearson Education 2010. Das Buch war auch Inspiration für diese Zusammenstellung.