__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 bytesDeklarowanie __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__")) # FalseZachowanie __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 objectPomiar 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 4dataclasses 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__")) # FalseKiedy 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 attributesSzybkie 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
- Jak tworzone są klasy Pythona
- Pisanie własnych metaklas
- Deskryptory: __get__, __set__, __delete__
- __slots__ i optymalizacja pamięci