Python Academy · Lektion

Skriva egna decorators

Skapa decorators med wrapper-funktioner och functools.wraps.

Lektion 2 av 414 steg

Skriva egna decorators är en gratis lektion i Python Academy på CoddyKit. Detta är lektion 2 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för Python Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Python Academy innehåller totalt 4 lektioner.

Introduktion

Dekoratorer är funktioner som omsluter andra funktioner och lägger till beteende före eller efter dem utan att ändra originalet.

Vad är en dekorator?

@decorator ovanför en funktion är syntaktiskt socker för: func = decorator(func). Dekoratorn tar emot funktionen och returnerar en wrapper.
def shout(func):
    def wrapper(*a, **kw):
        result = func(*a, **kw)
        return str(result).upper()
    return wrapper
@shout
def greet(name): return f'hello {name}'
print(greet('Alice'))

Wrapper-mönstret

Wrapper-funktionen har samma signatur som originalet. Den anropar originalet inuti och lägger till beteende runt det.
def timer(func):
    import time
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        print(f'{func.__name__} took {time.time()-start:.4f}s')
        return result
    return wrapper
@timer
def slow(): import time; time.sleep(0.01)
slow()

functools.wraps

@wraps(func) på wrappern bevarar originalfunktionens __name__, __doc__ och __annotations__.
from functools import wraps
def log(func):
    @wraps(func)
    def wrapper(*a, **kw):
        print(f'calling {func.__name__}')
        return func(*a, **kw)
    return wrapper
@log
def add(a, b): return a + b
print(add.__name__)
add(1, 2)

Dekorator med argument

En dekorator med argument kräver ytterligare ett omslutningslager: en fabriksfunktion som tar emot argumenten och returnerar dekoratorn.
def repeat(n):
    def decorator(func):
        from functools import wraps
        @wraps(func)
        def wrapper(*a, **kw):
            for _ in range(n): func(*a, **kw)
        return wrapper
    return decorator
@repeat(3)
def hi(): print('hi')
hi()

Stapla dekoratorer

Flera dekoratorer staplas underifrån och upp: @d2 @d1 betyder func = d2(d1(func)). Den yttersta (översta) körs sist.
def bold(f):
    from functools import wraps
    @wraps(f)
    def w(*a,**k): return '<b>' + f(*a,**k) + '</b>'
    return w
def italic(f):
    from functools import wraps
    @wraps(f)
    def w(*a,**k): return '<i>' + f(*a,**k) + '</i>'
    return w
@bold
@italic
def text(): return 'hello'
print(text())

Klassbaserad dekorator

En klass med __call__ kan vara en dekorator. Den lagrar tillstånd mellan anrop.
class Counter:
    def __init__(self, func): self.func,self.count=func,0
    def __call__(self, *a, **kw):
        self.count+=1
        return self.func(*a, **kw)
@Counter
def greet(name): return f'hi {name}'
greet('Alice'); greet('Bob')
print(greet.count)

Memoiseringsdekorator

Cachelagra tidigare resultat för att undvika att beräkna om dem: if args in cache: return cache[args]. functools.lru_cache gör detta inbyggt.
from functools import lru_cache
@lru_cache(maxsize=None)
def fib(n):
    if n < 2: return n
    return fib(n-1) + fib(n-2)
print(fib(30))

Behörighetsdekorator

Dekoratorer används ofta för åtkomstkontroll: kontrollera om användaren är inloggad innan funktionen körs.
def requires_auth(func):
    from functools import wraps
    @wraps(func)
    def wrapper(user, *a, **kw):
        if not user.get('authenticated'):
            raise PermissionError('Not authenticated')
        return func(user, *a, **kw)
    return wrapper
@requires_auth
def dashboard(user): return 'Welcome!'
try: dashboard({'authenticated': False})
except PermissionError as e: print(e)

Försöksdekorator

Omslut en funktion för att försöka igen vid fel: for _ in range(retries): try: return func() except Exception: pass
import random
from functools import wraps
def retry(times=3):
    def dec(func):
        @wraps(func)
        def wrapper(*a, **kw):
            for i in range(times):
                try: return func(*a, **kw)
                except Exception as e:
                    if i==times-1: raise
        return wrapper
    return dec
@retry(3)
def flaky():
    if random.random()<0.7: raise ValueError
    return 'ok'
try: print(flaky())
except ValueError: print('failed')

Bästa praxis för dekoratorer

Använd alltid @functools.wraps. Låt varje dekorator ha ett enda ansvarsområde. Dokumentera vad den lägger till. Testa dekoratorn separat från den dekorerade funktionen.
from functools import wraps
def validate_positive(func):
    @wraps(func)
    def wrapper(x, *a, **kw):
        if x <= 0: raise ValueError(f'{x} must be positive')
        return func(x, *a, **kw)
    return wrapper
@validate_positive
def sqrt(x): return x**0.5
print(sqrt(9))

Snabb kontroll

Vad gör @functools.wraps(func) när den används på en wrapper?

Sammanfattning

Dekoratorer: func = decorator(func). Använd wrapper(*args, **kwargs). @wraps bevarar metadata. Parametriserade dekoratorer lägger till ytterligare ett omslutningslager. Stapla flera @decorators.

Fortsätt

Utmärkt framsteg! Fortsätt för att behärska nästa koncept.
Gratis att börja

Lär dig Python med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
76
Lektioner
320

Vanliga frågor

Är lektionen ”Skriva egna decorators” gratis?

Ja – hela texten till ”Skriva egna decorators” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i Python Academy, kan Ni uppgradera till CoddyKit PRO. Kursen i Python Academy innehåller totalt 4 lektioner.

Vad lär jag mig i ”Skriva egna decorators”?

Skapa decorators med wrapper-funktioner och functools.wraps. Ni övar på Python Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig Python Academy?

Du behöver inga förkunskaper. Utbildningen i Python Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 2 av 4.

Hur lång tid tar lektionen ”Skriva egna decorators”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här Python Academy-lektionen?

Ja. Varje Python Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. Funktioner som förstaklassobjekt
  2. Skriva egna decorators
  3. Decorators: @property
  4. @classmethod och @staticmethod
← Tillbaka till Python Academy