Dekoratory
Dekoratory to specjalne funkcje, które pozwalają na rozszerzanie funkcjonalności innych funkcji lub klas bez modyfikacji ich kodu. Umożliwiają one dodanie dodatkowego działania przed lub po wykonaniu oryginalnej funkcji, co jest przydatne w wielu scenariuszach, takich jak logowanie, uwierzytelnianie, zarządzanie czasem wykonania funkcji itp.
Podstawowe działanie
Dekorator to funkcja, która przyjmuje inną funkcję jako argument i zwraca nową funkcję, która rozszerza działanie oryginalnej. Dzięki temu możemy dodać dodatkową funkcjonalność bez modyfikowania ciała dekorowanej funkcji.
def przykladowy_dekorator(funkcja):
def wrapper():
print("Dodatkowa funkcjonalność przed wywołaniem funkcji.")
funkcja()
print("Dodatkowa funkcjonalność po wywołaniu funkcji.")
return wrapper
Dekorowanie funkcji
Aby zastosować dekorator, można go „przykleić” do funkcji za pomocą znaku @
.
@przykladowy_dekorator
def moja_funkcja():
print("Oryginalna funkcja.")
moja_funkcja()
Dekorator z argumentami funkcji
Aby stworzyć dekorator, który obsłuży funkcje z argumentami, wystarczy zmodyfikować wewnętrzną funkcję wrapper
, aby przyjmowała dowolne argumenty i przekazywała je do oryginalnej funkcji.
def przykladowy_dekorator(funkcja):
def wrapper(*args, **kwargs):
print("Przed wywołaniem funkcji.")
wynik = funkcja(*args, **kwargs)
print("Po wywołaniu funkcji.")
return wynik
return wrapper
@przykladowy_dekorator
def dodaj(a, b):
return a + b
print(dodaj(3, 5))
Dekorowanie klas
Dekoratory mogą być również stosowane do całych klas, modyfikując ich zachowanie lub dodając dodatkowe funkcje. Dekorator klasy przyjmuje klasę jako argument i zwraca zmodyfikowaną wersję tej klasy.
def dodaj_metode(cls):
cls.nowa_metoda = lambda self: "Nowa metoda w klasie!"
return cls
@dodaj_metode
class MojaKlasa:
def __init__(self):
self.wartosc = 42
# Tworzenie instancji i użycie dodanej metody
obiekt = MojaKlasa()
print(obiekt.nowa_metoda()) # Nowa metoda w klasie!
Typowe zastosowania dekoratorów
Logowanie
Logowanie - automatyczne logowanie wywołań funkcji.
def loguj(funkcja):
def wrapper(*args, **kwargs):
print(f"Wywołano funkcję: {funkcja.__name__} z argumentami: {args}, {kwargs}")
return funkcja(*args, **kwargs)
return wrapper
Uwierzytelnianie
Uwierzytelnianie – sprawdzanie uprawnień przed wykonaniem funkcji.
def wymaga_uprawnien(funkcja):
def wrapper(*args, **kwargs):
if not uzytkownik_ma_uprawnienia():
raise PermissionError("Brak uprawnień!")
return funkcja(*args, **kwargs)
return wrapper
Mierzenie czasu wykonania funkcji
Czas wykonania funkcji – pomiar czasu, jaki zajmuje wykonanie funkcji.
import time
def zmierz_czas(funkcja):
def wrapper(*args, **kwargs):
start = time.time()
wynik = funkcja(*args, **kwargs)
end = time.time()
print(f"Czas wykonania: {end - start} sekund")
return wynik
return wrapper
Zadania
Stwórz program (to również może być po prostu jeden plik), w którym zdefiniujesz dekorator oraz przedstawisz jego działanie.
Ma to być dekorator, który zmierzy i wyświetli czas wykonania dekorowanej funkcji. Dekorator powinien przyjmować jeden argument, który określa jednostkę czasu (sekundy lub mikrosekundy) dla wyniku.
Wymagania:
- Ma przyjmować argument o nazwie unit o wartości 'seconds' lub 'microseconds', określający jednostkę, w której ma być wyświetlony czas wykonania funkcji.
- Ma mierzyć czas wykonania dekorowanej funkcji.
- Ma wyświetlić czas wykonania funkcji w wybranej jednostce po zakończeniu jej wykonania.