__slots__ is een speciale klasse-attribuut dat de set van toegestane attributen van een instantie beperkt, geheugen bespaart en de toegang tot attributen versnelt. Het gebruik van __slots__ is vooral relevant voor een groot aantal vergelijkbare objecten.
Geschiedenis van de kwestie:
De opkomst van __slots__ is gerelateerd aan het feit dat elke instantie van een Python-object standaard een attributenwoordenboek (__dict__) heeft, wat handig is maar veel geheugen kost. Voor een miljoen objecten met een klein aantal velden ontstaat er aanzienlijke overhead.
Probleem:
Instanties van een normale klasse kunnen dynamisch worden uitgebreid, wat handig is, maar inefficiënt. Het gebruik van __slots__ beperkt het dynamisch toevoegen van nieuwe attributen, verwijdert de instantie-attributenwoordenboek, bespaart geheugen en versnelt de toegang.
Oplossing:
Definieer de lijst van toegestane velden in het attribuut __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' object heeft geen attribuut 'z'
Belangrijke kenmerken:
Kan ik een instantie van een klasse met slots maken en later een attribuut toevoegen dat niet in de lijst staat?
Nee. Bij het proberen toe te voegen van een attribuut dat ontbreekt in de lijst slots wordt een AttributeError opgegooid. Dit legt beperkingen op aan de uitbreidbaarheid van het object.
Kan ik een klasse met slots overerven en nieuwe velden toevoegen?
Ja, maar elke afgeleid klasse moet zijn eigen slots verklaren. In dit geval worden de ouder- en huidige slots samengevoegd. Als er echter geen slots in de afgeleide klasse worden verklaard, krijgt de afstammeling opnieuw een dict!
Werkt slots voor onveranderlijke (immutable) types?
Ja, maar het is nodig om extra maatregelen te nemen om het slot-object onveranderlijk te maken (bijvoorbeeld via property zonder setter).
Een gewone klasse voor een punt:
class Point: def __init__(self, x, y): self.x = x self.y = y points = [Point(i, i) for i in range(1_000_000)]
Voordelen:
Nadelen:
Een vergelijkbare klasse, maar met 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)]
Voordelen:
Nadelen: