Klasa łączy dane i to, co z nimi robisz
Klasa pozwala zdefiniować rodzaj rzeczy (użytkownika, konto bankowe, konfigurację, żądanie) oraz wszystko, co ta rzecz powinna umieć. Rzecz to instancja klasy. Działania nazywa się metodami.
Oto najprostsza możliwa klasa:
Po kolei:
class User:rozpoczyna definicję klasy. Nazwy klas zapisuje się zwyczajowo w PascalCase.__init__to inicjalizator. Uruchamia się automatycznie, gdy tworzysz nową instancję. Ustawia atrybuty instancji przezself.whatever = ....greetto metoda. Przezselfmetoda odwołuje się do instancji, na której ją wywołano.User("Rosa", "rosa@example.com")tworzy instancję. Python wywołuje__init__, ustawiającselfna nową instancję i przekazując pozostałe argumenty.user.greet()wywołuje metodę. Python automatycznie przekazujeuserjakoself.
self to po prostu pierwszy argument
self nie jest słowem kluczowym. To nazwa, jaką nadaje się pierwszemu parametrowi metod instancji, czyli instancji, na której działa metoda. Nazwę można wybrać dowolnie, ale wszyscy używają self, bo tak robią wszyscy.
Każda metoda instancji przyjmuje self jako pierwszy parametr. Dzięki temu metoda wie, z której instancji czytać i którą modyfikować.
Dodawanie zachowania
Metody mogą odczytywać i zmieniać stan:
__repr__ to kolejna metoda specjalna: punkt zaczepienia typu "jak pokazać ten obiekt przy wypisywaniu?". Dobra definicja bardzo się opłaca podczas debugowania.
Atrybuty klasy a atrybuty instancji
Atrybuty zdefiniowane w ciele klasy (poza __init__) są wspólne dla wszystkich instancji. Atrybuty przypisane do self należą do pojedynczej instancji:
Atrybutów klasy używaj do wartości naprawdę wspólnych: stałych, liczników, konfiguracji. Dane konkretnej instancji umieszczaj w __init__.
Dziedziczenie
Klasa może dziedziczyć po innej klasie, dostając za darmo jej metody i atrybuty oraz dodając lub nadpisując to, co trzeba:
super() daje dostęp do klasy nadrzędnej. Często używa się go w __init__, by zainicjalizować atrybuty rodzica przed dodaniem własnych:
Dziedziczenie jest przydatne, ale łatwo go nadużyć. Początkujący programiści Pythona często sięgają po dziedziczenie tam, gdzie kompozycja (przechowywanie obiektu jako atrybutu) byłaby czytelniejsza. Zacznij od płaskiej struktury klas, a dziedziczenie wprowadzaj dopiero przy prawdziwej relacji "jest rodzajem".
Strona o dziedziczeniu w Pythonie idzie dalej: rozszerzanie metody rodzica przez super(), isinstance i issubclass, abstrakcyjne klasy bazowe, wielodziedziczenie i kolejność rozwiązywania metod.
Dataclasses: wygodniejszy wybór dla rekordów
Gdy klasa ma głównie przechowywać kilka atrybutów z porównywaniem i czytelną reprezentacją, @dataclass oszczędza mnóstwo powtarzalnego kodu:
Porównaj to z ręcznym pisaniem __init__, __repr__ i __eq__. Dataclasses to właściwy pierwszy wybór, gdy alternatywą jest class Thing, w której jest tylko __init__ ustawiający atrybuty.
Właściwości: atrybuty obliczane
Czasem chcesz "atrybutu", który tak naprawdę jest obliczany. @property sprawia, że wygląda to jak zwykły dostęp do atrybutu:
Używaj właściwości tam, gdzie pojawiłoby się obj.get_something(): zamiana na właściwość sprawia, że API jest bardziej naturalne. Nie ukrywaj za nimi kosztownych operacji, bo użytkownik oczekuje, że dostęp do atrybutu jest szybki.
Prywatne umownie
Python nie ma prawdziwej prywatności. Umownie atrybuty zaczynające się od podkreślenia są przeznaczone do użytku wewnętrznego, a czytelnicy nie powinni ich ruszać spoza klasy:
class Cache:
def __init__(self):
self._store = {}
def put(self, key, value):
self._store[key] = value
def get(self, key, default=None):
return self._store.get(key, default)
Nazwy z podwójnym podkreśleniem (__name) włączają name mangling, które dokleja nazwę klasy do atrybutu. To narzędzie do unikania kolizji przy dziedziczeniu, a nie zabezpieczenie.
Kiedy nie używać klasy
Jeśli masz tylko zestaw powiązanych danych, wystarczy dataclass, zwykły słownik albo named tuple. Jeśli masz tylko jedną funkcję, nie potrzebuje ona klasy. Po klasy sięgaj, gdy masz jednocześnie stan i zachowanie, które są ze sobą związane, zwłaszcza gdy będziesz mieć wiele instancji tego samego rodzaju.
Przykład na koniec
Mały bufor logów przypominający plik:
Zwróć uwagę na __len__, kolejną metodę magiczną. Jej zdefiniowanie sprawia, że działa len(logger), bo len(x) to w rzeczywistości wywołanie x.__len__(). Python ma dziesiątki takich punktów zaczepienia, a poznasz je, gdy będą potrzebne.
Najczęściej zadawane pytania
Czym jest klasa w Pythonie?
Klasa to szablon do tworzenia obiektów, które łączą dane (atrybuty) i zachowanie (metody). class User: definiuje klasę User, a User(...) tworzy instancję. Klasy to główne narzędzie Pythona do modelowania rzeczy, które mają zarówno stan, jak i zachowanie.
Co oznacza self w Pythonie?
self to pierwszy parametr każdej metody instancji. Gdy wywołujesz user.greet(), Python przekazuje instancję user jako self. Wewnątrz metody self.name odwołuje się do atrybutu name tego użytkownika. Nazwa self to konwencja, a nie słowo kluczowe, ale używa jej każdy programista Pythona.
Czy Python jest językiem obiektowym?
Tak, w Pythonie wszystko jest obiektem, łącznie z liczbami, napisami i funkcjami. Możesz programować obiektowo, gdy to pasuje, ale Python cię do tego nie zmusza. Wiele prawdziwych programów w Pythonie używa klas oszczędnie i tam, gdzie się da, woli zwykłe funkcje i struktury danych.