Przejdź do treści głównej
Średnio zaawansowany Python2026-07-29 · 10 min czytania

Wyjaśnienie dekoratorów Pythona: od @property do logiki ponownej próby w 15 minut (2026)

Dekoratory to funkcja oddzielająca „zna Pythona” od „płynnie czyta Pythona”. Wyglądają magicznie, ale są mechaniczne: @dekorator w funkcji to dokładnie f = dekorator(f). To wszystko. Cała reszta w tym samouczku polega na tym, że jedna linia ma różne kształty.

Teoria jednej linii

Kiedy piszesz:

▶ PYTHONeditable · runs in your browser

Python przekształca to w:

▶ PYTHONeditable · runs in your browser

To jest cała mechanika. @nazwa_dekoratora powyżej def uruchamia nazwa_dekoratora = nazwa_dekoratora(nazwa_dekoratora) po definicji. Jeśli to zinternalizujesz, dekoratorzy przestaną być tajemniczy na zawsze.

Pisanie pierwszego dekoratora (60 sekund)

Dekorator to dowolny obiekt wywoływalny, który przyjmuje funkcję i zwraca funkcję. Typowy kształt:

▶ PYTHONeditable · runs in your browser

*args, **kwargs w opakowaniu jest wzorcem obronnym — pozwala dekoratorowi pracować na dowolnej funkcji niezależnie od podpisu. Pomiń to, a otrzymasz komunikat „TypeError: wrapper() przyjmuje 0 argumentów pozycyjnych, ale podano 2” w chwili, gdy ktoś ozdobi funkcję parametrami.

Poprawka @functools.wraps

Jeden subtelny błąd: po dekorowaniu add.__name__ jest `opakowaniem'', a nie `dodawaniem''. Dokumenty i wskazówki dotyczące typów również znikają. Poprawka polega na jednym imporcie:

▶ PYTHONeditable · runs in your browser

Zasada: każdy dekorator, który napiszesz, powinien używać `@functools.wraps(fn)`. Kosztuje jedną linię i zapobiega całej kategorii problemów związanych z debugowaniem (introspekcja, urządzenia pytest, formatery logging, pickle — wszystko bez tego psuje się cicho).

Cztery dekoratory, które zobaczysz w każdej bazie kodu

1. @właściwość — obliczane atrybuty

▶ PYTHONeditable · runs in your browser

@właściwość sprawia, że metoda jest wywoływalna tak, jakby była atrybutem. Idealny do wartości pochodnych tylko do odczytu. Istnieje również ścieżka zapisu @area.setter, ale 90% zastosowań @property jest tylko do odczytu.

2. @metoda statyczna i @metoda klasy

▶ PYTHONeditable · runs in your browser

@classmethod pobiera cls (samą klasę) i jest używane dla alternatywnych konstruktorów. @staticmethod nie oferuje niczego specjalnego i jest zwykłą funkcją, która po prostu żyje w przestrzeni nazw klasy.

3. @functools.cache — zapamiętywanie

▶ PYTHONeditable · runs in your browser

Jeden z najpotężniejszych dekoratorów stdlib. Automatycznie zapamiętuje funkcję na podstawie jej argumentów. Wymaga, aby wszystkie argumenty mogły być mieszane (żadnych list/dykt jako argumentów — użyj krotek).

4. @dataclasses.dataclass — eliminacja szablonów

▶ PYTHONeditable · runs in your browser

@dataclass odczytuje adnotacje typu na poziomie klasy i automatycznie generuje __init__, __repr__, __eq__ i (przy frozen=True) __hash__. To największa pojedyncza poprawa jakości życia w Pythonie 3.7+.

Pisanie dekoratora @retry (przykład z życia wziętego)

Dekorator, który ponawia próbę wykonania funkcji w przypadku niepowodzenia z wykładniczym wycofywaniem:

▶ PYTHONeditable · runs in your browser

Zwróć uwagę na trzy zagnieżdżone funkcje: retry akceptuje argumenty konfiguracyjne i zwraca dekorator; dekorator akceptuje funkcję i zwraca wrapper; wrapper uruchamia pętlę ponawiania prób. Ten trójwarstwowy wzór wygląda tak, jak każdy dekorator z argumentami — zapamiętaj kształt, a nie konkretny przykład.

Dekoratory oparte na klasach (rzadkie, ale przydatne)

Dekorator jest dowolny. Klasy z __call__ też działają:

▶ PYTHONeditable · runs in your browser

Używaj, gdy dekorator musi utrzymać stan, który przetrwa pojedyncze wywołanie (licznik, pamięć podręczna, segment z limitem szybkości).

Typowe pułapki

1. Zapomnij o `@functools.wraps` — introspekcja przerywa ciszę.

2. Zmienne domyślne argumenty w samym dekoratorze — tutaj również pojawia się klasyczny błąd def wrapper(x, cache=[]).

3. Dekorowanie metod bez akceptowania „ja” — pamiętaj, „ja” to tylko argument pozycyjny; *args, **kwargs łapie to dobrze.

4. Kolejność ma znaczenie podczas układania: @a\n@b\ndef f() to f = a(b(f)). Czytaj stosy od dołu do góry.

Ćwicz

Napisz dekorator @timing, który wypisuje czas działania opakowanej funkcji, a następnie zastosuj go do funkcji obliczającej sumę(zakres(10_000_000)). Cały dekorator składa się z 8 linii z functools.wraps + time.perf_counter.


Kiedy już zinternalizujesz, że @x to f = x(f), dekoratory staną się jedną z najbardziej produktywnych funkcji Pythona. Są wszędzie w prawdziwych bazach kodu: trasy Flask/FastAPI (@app.route), urządzenia pytest (@pytest.fixture), widoki Django (@login_required), walidatory Pydantic (@field_validator). Nauczenie się ich samodzielnego pisania odblokowuje możliwość czytania każdego z nich.

Następny krok: 10 praktycznych lekcji dekoratora — zbuduj od podstaw @retry, @memoise, @rate_limit i @requires_auth od podstaw z prawdziwym Pythonem uruchomionym w Twojej przeglądarce.

Gotowy, aby spróbować?

15 lekcji gratis po darmowej rejestracji – bez karty. Wypróbuj platformę i podejmij decyzję.

Zacznij bezpłatnie →

Or unlock every lesson

Pro — $12/mo, unlimited AI, cancel any time. Refund within 14 days worldwide.

See Pro plans →

Get one Python lesson + one career idea every Friday

No spam, no "buy our course now". Three bullets, every Friday. Unsubscribe with one click.