__slots__ ist ein spezielles Attribut einer Klasse, das die zulässigen Attribute einer Instanz einschränkt, Speicher spart und den Zugriff auf Attribute beschleunigt. Die Verwendung von __slots__ ist besonders relevant für eine große Anzahl ähnlicher Objekte.
Hintergrund:
Die Einführung von __slots__ hängt damit zusammen, dass standardmäßig jede Instanz eines Python-Objekts ein Wörterbuch von Attributen (__dict__) hat, was praktisch, aber speicherintensiv ist. Bei einer Million Objekte mit einer kleinen Anzahl von Feldern entsteht ein erheblicher Overhead.
Problem:
Instanzen einer normalen Klasse können dynamisch erweitert werden, was praktisch, aber ineffizient ist. Die Verwendung von __slots__ schränkt das dynamische Hinzufügen neuer Attribute ein, entfernt das instanzspezifische Attribut-Wörterbuch, spart Speicher und beschleunigt den Zugriff.
Lösung:
Definieren Sie eine Liste der erlaubten Felder im Attribut __slots__:
class Point: __slots__ = ('x', 'y') def __init__(self, x, y): self.x = x self.y = y p = Point(1, 2) p.z = 3 # AttributeError: 'Point' Objekt hat kein Attribut 'z'
Wesentliche Merkmale:
Kann man eine Instanz einer Klasse mit slots erstellen und dann ein Attribut hinzufügen, das nicht in der Liste ist?
Nein. Beim Versuch, ein Attribut hinzuzufügen, das in der Liste der slots fehlt, wird ein AttributeError ausgelöst. Dies schränkt die Erweiterbarkeit des Objekts ein.
Kann man eine Klasse mit slots erben und neue Felder hinzufügen?
Ja, aber jeder Nachkomme muss seine eigenen slots deklarieren. Dabei werden die Eltern- und aktuellen slots kombiniert. Wenn slots im Nachkommen nicht deklariert werden, hat der Nachkomme jedoch wieder ein dict!
Funktioniert slots für unveränderliche (immutable) Typen?
Ja, aber es müssen zusätzliche Maßnahmen ergriffen werden, um das Slot-Objekt unveränderlich zu machen (zum Beispiel über property ohne Setter).
Normale Klasse für einen Punkt:
class Point: def __init__(self, x, y): self.x = x self.y = y points = [Point(i, i) for i in range(1_000_000)]
Vorteile:
Nachteile:
Ähnliche Klasse, aber mit Slots:
class Point: __slots__ = ('x', 'y') def __init__(self, x, y): self.x = x self.y = y points = [Point(i, i) for i in range(1_000_000)]
Vorteile:
Nachteile: