Klasy i obiekty Pythona: samouczek 2026
Większość samouczków Python OOP uczy składni i pomija model mentalny. Ten działa odwrotnie — wyjdziesz z jasnym obrazem tego, czym jest klasa w czasie wykonywania, kiedy sięgnąć po @dataclass zamiast ręcznie pisać __init__ i jak naprawdę działa self (to nie jest magia).
Omówimy: czteroliniową minimalną wykonalną klasę, dlaczego „self” jest parametrem, atrybuty klasy vs instancji (błąd nr 1 dla początkujących), sześć metod dunder, które zobaczysz wszędzie, „@dataclass” jako współczesną wartość domyślną i twardą regułę określającą, kiedy zostawić klasy w spokoju i użyć zwykłej funkcji.
Model mentalny: klasa to fabryka
Klasa w Pythonie to fabryka produkująca obiekty. Za każdym razem, gdy wywołujesz „Rect(3, 4)”, Python tworzy nowy obiekt z własną pamięcią i przekazuje go z powrotem.
Ot cała mechanika. Klasa jest planem; każde wywołanie Rect(...) jest stemplem planu w świeżej pamięci RAM.
„self” to tylko parametr
Zamieszanie numer 1 dla osób pochodzących z JS lub Ruby: „self” w Pythonie jest wyraźne. Pierwszym parametrem każdej metody jest odwołanie do wywoływanej instancji.
Zatem „c.bump()” jest cukrem składniowym dla „Counter.bump(c)”. Python przekazuje instancję jako pierwszy argument. Można to nazwać „ja”, „to” lub „foo” — „ja” to konwencja, a nie słowo kluczowe. Trzymaj się „self” (PEP 8), aby inni programiści Pythona mogli przeczytać Twój kod.
Pułapka atrybutów klasy i instancji
Najczęstszy błąd Pythona OOP w bazie kodu dla początkujących:
items = [] w zakresie klasy tworzy JEDNĄ listę współdzieloną przez każdą instancję. a.add("milk") mutuje, więc b.items widzi tę samą listę.
Reguła: inicjuj stan zmienny w `__init__`, a nie w zakresie klasy.
Ten błąd był wysyłany do środowiska produkcyjnego częściej, niż przyznałby jakikolwiek programista Pythona. Uważaj na listy, dyktatury i zestawy w zakresie klasy.
Sześć metod, które zobaczysz wszędzie
Metody Dundera (__name__) to haki przeciążające operatory Pythona. Te sześć obejmuje 95% tego, co spotkasz:
1. __init__(self, ...) — konstruktor
Uruchamia się po utworzeniu obiektu. Ustaw tutaj atrybuty instancji. Nie zwracaj niczego (Python wymusza opcję „Brak”).
2. __repr__(self) — ciąg znaków skierowany do programisty
Wywoływane przez print(x), jeśli brakuje __str__ i zawsze przez REPL. Celuj w coś, co możesz wkleić z powrotem do Pythona, aby odtworzyć obiekt:
3. __eq__(self, other) — równość
Bez tego Rect(3, 4) == Rect(3, 4) zwraca False (domyślnie jest to tożsamość). Porównaj pole po polu:
4. __hash__(self) — haszowalność
Jeśli zastąpisz __eq__, MUSISZ także zastąpić __hash__ lub Python ustawi __hash__ = None (obiekt nie będzie mógł być haszowany). Najprościej: zwrot hash((self.width, self.height)).
5. __len__(self) — dla len(obj)
Sprawia, że len(cart) == 5 działa.
6. __iter__(self) — dla for x w obj:
Zwróć iterator. yield wewnątrz sprawia, że klasa jest iterowalna:
@dataclass — współczesna wartość domyślna
Jeśli Twoja klasa to głównie posiadacz danych (trzy pola, __init__, __repr__, __eq__), przestań pisać ten schemat. @dataclass generuje to wszystko na podstawie adnotacji typu:
To są wygenerowane __init__, __repr__ i __eq__. Dodaj @dataclass(frozen=True), aby uczynić obiekt niezmiennym ORAZ uzyskaj __hash__ za darmo.
Zasada: sięgnij najpierw po „@dataclass”. Twórz ręcznie tworzone klasy tylko wtedy, gdy potrzebujesz metod, które nie są metodami dostępu do atrybutów.
__slots__ — optymalizacja pamięci (zaawansowane)
Domyślnie każda instancja zawiera __dict__, dzięki czemu można dodać dowolne atrybuty. __slots__ zamienia, które wymagają stałej struktury na poziomie C — mniejsze zużycie pamięci RAM i szybszy dostęp do atrybutów:
Użyj __slots__, gdy: (a) tworzysz miliony instancji i problemy z pamięcią RAM, lub (b) chcesz wychwycić literówkę przy przypisywaniu atrybutów w czasie wykonywania. W przeciwnym razie pomiń go — domyślnie wyłącza pikle i w subtelny sposób łamie dziedziczenie wielokrotne.
Kiedy wyjść z zajęć w spokoju
Twarda zasada: jeśli twoja klasa ma JEDNĄ metodę plus `__init__`, prawdopodobnie powinna to być funkcja.
Klasy zyskują na znaczeniu, gdy przechowują state w wielu wywołaniach metod lub gdy implementują dobrze zdefiniowany protokół (__iter__, __enter__, __eq__ itp.). Logika jednorazowa jest funkcją.
Dziedziczenie — używaj go oszczędnie
Dziedziczenie jest realne, ale nadużywane. W Pythonie 2026 preferuj kompozycję — trzymaj inny obiekt jako atrybut zamiast dziedziczyć po nim:
Dziedzicz tylko wtedy, gdy masz prawdziwą relację „jest-a” ORAZ chcesz zastąpić zachowanie. NamedRect, który dziedziczy z Rect i dodaje pole name, jest w porządku. Budowanie pięciopoziomowej hierarchii dziedziczenia dla klasy logiki biznesowej to kod, który rozwikłasz w ciągu 6 miesięcy.
Klasy to jedna z najpotężniejszych funkcji Pythona i jedna z najłatwiejszych do nadmiernego użycia. Model mentalny, który pomaga: klasa jest fabryką obiektów, „self” to zwykły parametr, zmienny stan przechodzi do „__init__”, najpierw sięgnij po „@dataclass” i wróć do funkcji, gdy klasa ma mniej niż dwie metody przenoszące stan.
Następny krok: 30 praktycznych lekcji OOP obejmujących zajęcia, @dataclass, dziedziczenie a kompozycję i metody dunder — z prawdziwym Pythonem działającym w Twojej przeglądarce i mentorem AI na każdym kroku.