Dekoratører i Python

Dekoratører i Python

Denne artikkelen forklarer dekoratører i Python.

YouTube Video

Dekoratører i Python

Python-dekoratører er en kraftig funksjon brukt for å legge til ekstra funksjonalitet til funksjoner eller metoder. Dekoratører lar deg legge til ny funksjonalitet uten å endre eksisterende kode, og forbedrer dermed gjenbruk og vedlikeholdsevnen av koden.

Grunnleggende om dekoratører

Python-dekoratører fungerer ved å ta en funksjon som et argument og returnere en ny funksjon med ekstra funksjonalitet. Ved å bruke dekoratører kan du enkelt legge til forbehandling eller etterbehandling til funksjoner.

Uten dekoratører krever endring av en funksjons oppførsel at du redigerer funksjonen direkte. Med dekoratører kan du utvide funksjonalitet uten å endre den opprinnelige implementeringen.

Grunnstrukturen til en dekoratør

 1def my_decorator(func):
 2    def wrapper():
 3        print("Before the function call")
 4        func()
 5        print("After the function call")
 6    return wrapper
 7
 8@my_decorator
 9def say_hello():
10    print("Hello!")
11
12say_hello()

I dette eksempelet fungerer my_decorator-funksjonen som en dekoratør og omgir say_hello-funksjonen. Dekoratøren brukes ved hjelp av @my_decorator-syntaksen, og når say_hello() kalles, utføres forhånds- og etterbehandlingen som dekoratøren gir automatisk.

Hvordan dekoratører fungerer

Dekoratorer fungerer gjennom følgende steg.

  1. Dekoratøren tar en funksjon (eller metode) som et argument.

  2. Den definerer en innpakningsfunksjon for å kjøre den opprinnelige funksjonen.

  3. Innpakningsfunksjonen utfører ekstra prosessering før eller etter at den opprinnelige funksjonen er kjørt.

  4. Dekoratøren returnerer innpakningsfunksjonen. Som et resultat blir den opprinnelige funksjonen erstattet med en ny, dekorert funksjon.

Dekoratører for funksjoner med argumenter

Når du bruker en dekoratør på en funksjon med argumenter, må innpakningsfunksjonen justeres for å akseptere disse argumentene.

 1def my_decorator(func):
 2    def wrapper(*args, **kwargs):
 3        print("Before the function call")
 4        result = func(*args, **kwargs)
 5        print("After the function call")
 6        return result
 7    return wrapper
 8
 9@my_decorator
10def greet(name):
11    print(f"Hello, {name}!")
12
13greet("Alice")

Ved å bruke *args og **kwargs er det mulig å håndtere funksjoner som aksepterer et vilkårlig antall argumenter og nøkkelordargumenter. Dette tillater at dekoratører kan brukes generisk på funksjoner med enhver type argumenter.

Eksempler på bruk av dekoratorer

Dekorator for logging

Dekoratorer brukes ofte for å legge til loggefunksjonalitet. For eksempel, ved å lage en dekorator som logger før og etter utførelsen av en funksjon, kan du registrere når funksjonen blir kalt og hvor lang tid det tar å utføre den.

 1import time
 2
 3def log_time(func):
 4    def wrapper(*args, **kwargs):
 5        start_time = time.time()
 6        print(f"Calling function '{func.__name__}'...")
 7        result = func(*args, **kwargs)
 8        end_time = time.time()
 9        print(f"Function '{func.__name__}' completed in {end_time - start_time} seconds")
10        return result
11    return wrapper
12
13@log_time
14def long_task(duration):
15    time.sleep(duration)
16    print("Task completed!")
17
18long_task(2)

I dette eksempelet måler log_time-dekoratoren kjøretiden til en funksjon og skriver den ut som en logg. long_task-funksjonen er pakket inn i dekoratoren, og dens kjøretid blir registrert under kjøring.

Dekorator for rettighetsstyring

Dekoratorer kan også brukes for rettighetsstyring. For eksempel kan du begrense behandling ved å sjekke om en bruker har spesifikke rettigheter.

 1def requires_permission(user_role):
 2    def decorator(func):
 3        def wrapper(*args, **kwargs):
 4            if user_role != "admin":
 5                print("Permission denied!")
 6                return
 7            return func(*args, **kwargs)
 8        return wrapper
 9    return decorator
10
11@requires_permission("admin")
12def delete_user(user_id):
13    print(f"User {user_id} has been deleted.")
14
15delete_user(123)  # Executed
16delete_user = requires_permission("guest")(delete_user)
17delete_user(456)  # Permission denied!

requires_permission-dekoratoren begrenser utførelsen av en funksjon basert på en brukers rolle. Ved å konsolidere slik logikk i en dekorator kan du forhindre at rettighetslogikk spres over hele koden din, noe som forbedrer lesbarheten.

Nesting av dekoratorer

Det er mulig å bruke flere dekoratorer. Når flere dekoratorer brukes på en enkelt funksjon, kjøres de i rekkefølge fra topp til bunn.

 1def uppercase(func):
 2    def wrapper(*args, **kwargs):
 3        result = func(*args, **kwargs)
 4        return result.upper()
 5    return wrapper
 6
 7def exclaim(func):
 8    def wrapper(*args, **kwargs):
 9        result = func(*args, **kwargs)
10        return result + "!"
11    return wrapper
12
13@uppercase
14@exclaim
15def greet(name):
16    return f"Hello, {name}"
17
18print(greet("Alice"))  # "HELLO, ALICE!"

I dette eksempelet brukes to dekoratorer på greet-funksjonen. @exclaim-dekoratoren legger til et utropstegn på slutten av strengen, og deretter konverterer @uppercase strengen til store bokstaver.

Dekoratorer for klassemåter

Dekoratorer kan også brukes med klassemåter. Dette er spesielt nyttig når du vil kontrollere oppførselen til metoder i en klasse. Når du bruker dekoratorer på klassemåter, må du være oppmerksom på argumenter som self eller cls.

 1def log_method_call(func):
 2    def wrapper(self, *args, **kwargs):
 3        print(f"Calling method '{func.__name__}'...")
 4        return func(self, *args, **kwargs)
 5    return wrapper
 6
 7class MyClass:
 8    @log_method_call
 9    def greet(self, name):
10        print(f"Hello, {name}")
11
12obj = MyClass()
13obj.greet("Bob")

I dette eksempelet brukes log_method_call-dekoratoren på greet-metoden for å skrive ut en logg når metoden kalles.

Forsiktighetsregler med dekoratorer

Det finnes noen hensyn når man bruker dekoratorer. Dekoratorer kan potensielt endre det opprinnelige navnet og dokumentasjonsstrengen til en funksjon (f.eks. __name__ eller __doc__), så det anbefales å bruke functools.wraps for å bevare denne informasjonen.

1import functools
2
3def my_decorator(func):
4    @functools.wraps(func)
5    def wrapper(*args, **kwargs):
6        print("Before the function call")
7        return func(*args, **kwargs)
8    return wrapper

Ved å bruke @functools.wraps sikrer du at metadataene til den opprinnelige funksjonen blir korrekt overført til innpakningsfunksjonen.

Sammendrag

Python-dekoratorer er et svært kraftig verktøy som lar deg kortfattet legge til ekstra funksjonalitet til funksjoner og metoder. De kan brukes i ulike scenarier for å redusere kode-duplisering og forbedre vedlikeholdbarhet og gjenbrukbarhet. Ved å forstå hvordan dekoratorer fungerer, kan du skrive mer effektiv og fleksibel kode.

Du kan følge med på artikkelen ovenfor ved å bruke Visual Studio Code på vår YouTube-kanal. Vennligst sjekk ut YouTube-kanalen.

YouTube Video