0Pricing
Python Academy · Lekcja

__slots__ i optymalizacja pamięci

Proszę używać __slots__, aby zmniejszyć narzut pamięci dla poszczególnych instancji.

__slots__ i optymalizacja pamięci to bezpłatna lekcja Python Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Python Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Python Academy zawiera 4 lekcji w sumie.

Narzut domyślnego __dict__

Domyślnie każda instancja Pythona przechowuje atrybuty w słowniku __dict__, co wiąże się ze znacznym narzutem pamięci — zwykle 200–400 bajtów na instancję.

import sys

class Point:
    def __init__(self, x, y): self.x, self.y = x, y

p = Point(1, 2)
print(sys.getsizeof(p.__dict__))   # ~200 bytes

Deklarowanie __slots__

Należy zdefiniować __slots__ jako sekwencję nazw atrybutów. Python przydzieli tablicę o stałym rozmiarze zamiast słownika, oszczędzając pamięć.

class SlottedPoint:
    __slots__ = ("x", "y")

    def __init__(self, x, y):
        self.x = x
        self.y = y

p = SlottedPoint(1, 2)
print(p.x, p.y)   # 1 2
# p.z = 3   # AttributeError: no __dict__

Oszczędność pamięci

Dzięki __slots__ każda instancja zwykle zajmuje o 30–50% mniej pamięci niż instancja oparta na słowniku — ma to duże znaczenie przy tworzeniu milionów obiektów.

import sys

class Reg:
    def __init__(self, x, y): self.x, self.y = x, y

class Slotted:
    __slots__ = ("x","y")
    def __init__(self, x, y): self.x, self.y = x, y

print(sys.getsizeof(Reg(1,2)))      # ~56 bytes + ~200 dict
print(sys.getsizeof(Slotted(1,2)))  # ~56 bytes (no dict)

Brak __dict__ domyślnie

Klasa korzystająca z __slots__ nie ma __dict__, dlatego po utworzeniu instancji nie można dodawać do niej dowolnych atrybutów.

class Config:
    __slots__ = ("host", "port")
    def __init__(self, h, p): self.host, self.port = h, p

c = Config("localhost", 8080)
# c.debug = True   # AttributeError
print(hasattr(c, "__dict__"))   # False

Zachowanie __dict__ z __slots__

Należy uwzględnić "__dict__" w __slots__, aby zachować słownik dla każdej instancji, a jednocześnie wstępnie zadeklarować typowe atrybuty jako sloty.

class Hybrid:
    __slots__ = ("x", "__dict__")

    def __init__(self, x):
        self.x = x

h = Hybrid(1)
h.extra = "dynamic"   # allowed
print(h.extra)

__weakref__ w __slots__

Klasy korzystające ze slotów tracą obsługę słabych odwołań. Należy dodać "__weakref__" do __slots__, aby ją ponownie włączyć.

import weakref

class Node:
    __slots__ = ("value", "__weakref__")
    def __init__(self, v): self.value = v

n = Node(42)
ref = weakref.ref(n)
print(ref())  # <Node object>

Dziedziczenie i __slots__

Jeśli klasa nadrzędna nie używa __slots__, klasa potomna nadal otrzymuje __dict__. Aby uzyskać pełną oszczędność, cała hierarchia musi definiować __slots__.

class Base:
    __slots__ = ("x",)

class Child(Base):
    __slots__ = ("y",)   # no __dict__

class WithoutSlots(Base):
    pass   # gets __dict__ from object

Pomiar pamięci

Należy użyć tracemalloc lub pympler, aby zmierzyć rzeczywiste zużycie pamięci przed dodaniem __slots__ i po nim.

import tracemalloc

tracemalloc.start()
points = [SlottedPoint(i, i) for i in range(100_000)]
current, peak = tracemalloc.get_traced_memory()
tracemalloc.stop()
print(f"Peak: {peak/1024/1024:.1f} MB")

__slots__ i serializacja za pomocą pickle

Obiekty korzystające ze slotów można serializować za pomocą pickle, jeśli zdefiniuje się __getstate__ i __setstate__, lub użyje domyślnego protokołu pickle, który od Python 3 automatycznie obsługuje sloty.

import pickle

class Point:
    __slots__ = ("x", "y")
    def __init__(self, x, y): self.x, self.y = x, y

p = Point(3, 4)
data = pickle.dumps(p)
p2 = pickle.loads(data)
print(p2.x, p2.y)   # 3 4

dataclasses z __slots__ — Python 3.10+

Należy przekazać slots=True do @dataclass, aby automatycznie wygenerować __slots__.

from dataclasses import dataclass

@dataclass(slots=True)
class Vector:
    x: float
    y: float

v = Vector(1.0, 2.0)
print(v.x, v.y)   # 1.0 2.0
print(hasattr(v, "__dict__"))   # False

Kiedy używać __slots__

Należy używać __slots__, gdy: tworzonych jest miliony instancji, pamięć jest ograniczona lub kluczowe znaczenie ma szybkość dostępu do atrybutów. W przypadku klas ogólnego przeznaczenia należy z niego zrezygnować, jeśli ważniejsza jest elastyczność.

# Good candidates:
# - Nodes in a large graph or tree
# - Records in a large dataset
# - High-frequency event objects

# Bad candidates:
# - Configuration objects added to ad-hoc
# - Classes that mix-in dynamic attributes

Szybkie sprawdzenie

Co się stanie przy próbie ustawienia atrybutu, którego nie wymieniono w __slots__, w instancji korzystającej ze slotów?

Podsumowanie

__slots__ zastępuje __dict__ instancji tablicą o stałym rozmiarze, oszczędzając 30–50% pamięci. Jeśli są potrzebne, należy uwzględnić "__dict__" lub "__weakref__". Aby uzyskać pełną oszczędność, cały łańcuch dziedziczenia musi korzystać z __slots__. W Pythonie 3.10+ należy użyć @dataclass(slots=True).

Często zadawane pytania

Czy lekcja „__slots__ i optymalizacja pamięci” jest bezpłatna?

Tak — pełny tekst „__slots__ i optymalizacja pamięci” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Python Academy, przejdź na CoddyKit PRO. Kurs Python Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „__slots__ i optymalizacja pamięci”?

Proszę używać __slots__, aby zmniejszyć narzut pamięci dla poszczególnych instancji. Ćwiczysz Python Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Python Academy?

Nie wymagamy żadnego doświadczenia. Python Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „__slots__ i optymalizacja pamięci”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Python Academy?

Tak. Każda lekcja Python Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Jak tworzone są klasy Pythona
  2. Pisanie własnych metaklas
  3. Deskryptory: __get__, __set__, __delete__
  4. __slots__ i optymalizacja pamięci
← Powrót do Python Academy