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:
  suite
__enter__(self) Wird ausgeführt, wenn der der Code-Block betreten wird.
with expression as variable:
  suite
__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