Python Academy · Lektion

Skrivning af brugerdefinerede decorators

Opret decorators med wrapper-funktioner og functools.wraps.

Lektion 2 af 414 trin

Skrivning af brugerdefinerede decorators er en gratis Python Academy-lektion på CoddyKit. Dette er lektion 2 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i Python Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Python Academy-kurset indeholder 4 lektioner i alt.

Introduktion

Dekoratorer er funktioner, der pakker andre funktioner ind og tilføjer adfærd før eller efter dem uden at ændre originalen.

Hvad er en dekorator?

@decorator over en funktion er syntaktisk sukker for: func = decorator(func). Dekoratoren modtager funktionen og returnerer 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 samme signatur som originalen. Den kalder originalen internt og tilføjer adfærd omkring den.
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å wrapperen bevarer den oprindelige funktions __name__, __doc__ og __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 argumenter

En dekorator med argumenter kræver endnu et niveau af indpakning: en fabriksfunktion, der tager argumenterne og returnerer dekoratoren.
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()

Stabling af dekoratorer

Flere dekoratorer stables nedefra og op: @d2 @d1 betyder func = d2(d1(func)). Den yderste dekorator øverst køres sidst.
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())

Klassebaseret dekorator

En klasse med __call__ kan være en dekorator. Den gemmer tilstand mellem kald.
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)

Dekorator til memoisering

Gem tidligere resultater i en cache for at undgå at beregne dem igen: if args in cache: return cache[args]. functools.lru_cache gør dette indbygget.
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))

Dekorator til adgangskontrol

Dekoratorer bruges ofte til adgangskontrol: Tjek, om brugeren er logget ind, før funktionen køres.
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)

Dekorator til genforsøg

Pak en funktion ind, så den prøves igen ved fejl: 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')

Bedste praksis for dekoratorer

Brug altid @functools.wraps. Giv hver dekorator ét formål. Dokumentér, hvad den tilføjer. Test dekoratoren separat fra den dekorerede funktion.
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))

Hurtigt tjek

Hvad gør @functools.wraps(func), når den anvendes på en wrapper?

Opsummering

Dekoratorer: func = decorator(func). Brug wrapper(*args, **kwargs). @wraps bevarer metadata. Parametriserede dekoratorer tilføjer endnu et niveau. Stabl flere @decorators.

Fortsæt

Fremragende fremskridt! Fortsæt for at få styr på det næste koncept.
Gratis at komme i gang

Lær Python med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
76
Lektioner
320

Ofte stillede spørgsmål

Er lektionen “Skrivning af brugerdefinerede decorators” gratis?

Ja — hele teksten til “Skrivning af brugerdefinerede decorators” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af Python Academy-kurset, skal du opgradere til CoddyKit PRO. Python Academy-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “Skrivning af brugerdefinerede decorators”?

Opret decorators med wrapper-funktioner og functools.wraps. Du øver dig i Python Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Python Academy?

Der kræves ingen tidligere erfaring. Python Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 2 af 4.

Hvor lang tid tager lektionen “Skrivning af brugerdefinerede decorators”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne Python Academy-lektion?

Ja. Alle Python Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Funktioner som first-class-objekter
  2. Skrivning af brugerdefinerede decorators
  3. @property-decoratoren
  4. @classmethod og @staticmethod
← Tilbage til Python Academy