programowanieBackend Python developer

Co to jest __slots__ w klasach Pythona, po co są potrzebne i jakie mają ograniczenia?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

__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:

  • Oszczędza pamięć dzięki braku dict i weakref domyślnie.
  • Określa ścisły zestaw dozwolonych pól.
  • Umożliwia przyspieszenie dostępu do atrybutów dzięki wstępnie przydzielonym slotom (nie wymaga przeszukiwania w dict).

Pytania z podstępem.

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).

Typowe błędy i antypatriony

  • Nie zadeklarować slots w klasie potomnej, psując efektywność pamięci.
  • Oczekiwać działania slots w przypadku wielokrotnego dziedziczenia — mogą wystąpić konflikty i błędy.
  • Próba serializacji obiektów ze slotami standardowymi metodami może być czasami utrudniona (na przykład, pickle wymaga dict).

Przykład z życia

Negatywny przypadek

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:

  • Elastyczne — można dodawać dowolne atrybuty.
  • Zrozumiałe dla nowicjuszy.

Wady:

  • menedżer zadań pokazuje zauważalnie zwiększone zużycie pamięci (do +20-30%).

Pozytywny przypadek

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:

  • Do 30% oszczędności pamięci na milionach obiektów.
  • Szybszy dostęp do pól.

Wady:

  • Obiekty stają się mało elastyczne: nie można dodać nowych atrybutów w locie.