__slots__ to specjalny atrybut klasy, który ogranicza zestaw dozwolonych atrybutów instancji, oszczędza pamięć i przyspiesza dostęp do atrybutów. Użycie __slots__ jest szczególnie istotne dla dużej liczby jednolitych obiektów.
Historia pytania:
Pojawienie się __slots__ wiąże się z tym, że domyślnie każdy egzemplarz obiektu Pythona ma słownik atrybutów (__dict__), co jest wygodne, ale kosztowne pod względem pamięci. Dla miliona obiektów z niewielkim zestawem pól pojawia się znaczący nadmiar.
Problem:
Egzemplarze zwykłej klasy mogą być dynamicznie rozszerzane, co jest wygodne, ale nieefektywne. Zastosowanie __slots__ ogranicza dynamiczne dodawanie nowych atrybutów, eliminuje słownik atrybutów instancji, oszczędza pamięć i przyspiesza dostęp.
Rozwiązanie:
Opisuj listę dozwolonych pól w atrybucie __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 has no attribute 'z'
Kluczowe cechy:
Czy można utworzyć egzemplarz klasy z slots i później dodać atrybut nie z listy?
Nie. Przy próbie dodania atrybutu, który nie znajduje się na liście slots, zostanie zgłoszony błąd AttributeError. Nakłada to ograniczenia na rozszerzalność obiektu.
Czy można dziedziczyć klasę z slots i dodać nowe pola?
Tak, ale każdy potomek musi deklarować swoje slots. Przy tym rodzicielskie i bieżące slots są łączone. Jednak jeśli nie zadeklarujesz slots w potomstwie, potomkowi znów pojawi się dict!
Czy slots działa dla typów niemodyfikowalnych (immutable)?
Tak, ale należy wprowadzić dodatkowe środki, aby uczynić obiekt slotowy niemodyfikowalnym (na przykład, przez property bez settera).
Zwykła klasa dla punktu:
class Point: def __init__(self, x, y): self.x = x self.y = y points = [Point(i, i) for i in range(1_000_000)]
Zalety:
Wady:
Analogiczna klasa, ale ze slotami:
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)]
Zalety:
Wady: