Python-decorateurs uitgelegd: van @property naar logica voor opnieuw proberen in 15 minuten (2026)
Decorateurs zijn het kenmerk dat ‘kent Python’ scheidt van ‘leest Python vloeiend’. Ze zien er magisch uit, maar ze zijn mechanisch: @decorator op een functie is precies f = decorateur(f). Dat is het. Al het andere in deze tutorial is dat één lijn in verschillende vormen wordt toegepast.
De éénregelige theorie
Wanneer je schrijft:
Python transformeert het in:
Dat is de hele monteur. @decorator_name boven een def voert def_name = decorateurnaam(def_naam) na de definitie uit. Als je dit internaliseert, zijn decorateurs voor altijd niet meer mysterieus.
Je eerste decorateur schrijven (60 seconden)
Een decorateur is een oproepbare functie die een functie aanneemt en een functie retourneert. De typische vorm:
De 'args, *kwargs' in de verpakking zijn een defensief patroon: het laat de decorateur aan elke functie werken, ongeacht de handtekening. Sla dit over en je krijgt 'TypeError: wrapper() neemt 0 positionele argumenten, maar er zijn er 2 gegeven' op het moment dat iemand een functie versiert met parameters.
De @functools.wraps oplossing
Eén subtiele bug: na het decoreren is add.__name__ `wrapper', niet `add'. Docstrings en typehints verdwijnen ook. De oplossing is één import:
Regel: elke decorateur die u schrijft, moet `@functools.wraps(fn)` gebruiken. Het kost één regel en voorkomt een hele categorie van debugging-pijn (introspectie, pytest-fixtures, logging-formatters, pickle – zonder dit alles gaat het stil).
De vier decorateurs die je in elke codebase ziet
1. @property — berekende attributen
@property maakt een methode aanroepbaar alsof het een attribuut is. Perfect voor alleen-lezen afgeleide waarden. Er is ook @area.setter voor het schrijfpad, maar 90% van het gebruik van @property is alleen-lezen.
2. @staticmethod en @classmethod
@classmethod krijgt cls (de klasse zelf) en wordt gebruikt voor alternatieve constructors. @staticmethod krijgt niets bijzonders en is een gewone functie die toevallig binnen de klassenaamruimte leeft.
3. @functools.cache — memoisatie
Een van de krachtigste stdlib-decorateurs. Onthoudt de functie automatisch op basis van zijn argumenten. Vereist dat alle argumenten hashbaar zijn (geen lijsten / dictaten als argumenten - gebruik tupels).
4. @dataclasses.dataclass — standaardverwijdering
@dataclass leest de annotaties van het klasseniveau en genereert automatisch __init__, __repr__, __eq__ en (met frozen=True) __hash__. Het is de grootste verbetering van de levenskwaliteit in Python 3.7+.
Een @retry-decorateur schrijven (voorbeeld uit de echte wereld)
Een decorateur die een functie bij falen opnieuw probeert met exponentiële uitstel:
Let op de drie geneste functies: retry accepteert de configuratieargs en retourneert decorator; decorator accepteert de functie en retourneert wrapper; wrapper voert de retry-lus uit. Dit drielaagse patroon is hoe elke decorateur-met-argumenten eruit ziet: onthoud de vorm, niet het specifieke voorbeeld.
Op klassen gebaseerde decorateurs (zeldzaam maar nuttig)
Een decorateur is altijd oproepbaar. Klassen met __call__ werken ook:
Te gebruiken wanneer de binnenhuisarchitect een status moet vasthouden die een enkele oproep overleeft (een teller, een cache, een tarieflimietbucket).
Veelvoorkomende valkuilen
1. `@functools.wraps` vergeten – introspectie breekt stil af.
2. Veranderlijke standaardargumenten in de decorateur zelf — de klassieke def wrapper(x, cache=[]) bug bijt hier ook.
3. Decoratiemethoden zonder 'zelf' te accepteren - onthoud dat 'zelf' slechts een positioneel argument is; *args, **kwargs vat het prima.
4. De volgorde is belangrijk bij het stapelen: @a\n@b\ndef f() is f = a(b(f)). Lees stapels van onder naar boven.
Oefenen
Schrijf een @timing-decorateur die afdrukt hoe lang het duurt voordat de ingepakte functie wordt uitgevoerd, en pas deze vervolgens toe op een functie die sum(range(10_000_000)) berekent. De hele decorateur bestaat uit 8 regels met functools.wraps + time.perf_counter.
Zodra je beseft dat @x f = x(f) is, worden decorateurs een van de meest productieve functies van Python. Ze zijn overal in echte codebases: Flask/FastAPI-routes ("@app.route"), pytest-armaturen ("@pytest.fixture"), Django-weergaven ("@login_required"), Pydantic-validators ("@field_validator"). Als je ze zelf leert schrijven, ontgrendel je de mogelijkheid om ze allemaal te lezen.
Volgende stap: 10 praktische lessen over decoreren — bouw @retry, @memoise, @rate_limit en @requires_auth helemaal opnieuw met echte Python in uw browser.