Оволодіння декораторами Python: Спрощуйте свій код за допомогою цього потужного інструменту

pic

Декоратори

Декоратори — одна з найелегантніших і найпотужніших особливостей Python. Вони дозволяють розробникам змінювати поведінку функції або методу без зміни їх коду. Якщо ви коли-небудь використовували Python-фреймворки, такі як Flask чи Django, то, ймовірно, вже використовували декоратори, навіть не усвідомлюючи цього.

У цьому блозі ми детально розглянемо концепцію декораторів у Python, пояснимо її через чіткі приклади та варіанти використання. Наприкінці ви не тільки зрозумієте, як працюють декоратори, але й дізнаєтесь, як написати власні.

Що таке декоратори?

Декоратор — це функція, яка приймає іншу функцію (або метод) як аргумент і розширює чи змінює її поведінку без явного модифікування. Уявіть це як обгортку, яка додає функціональність до існуючого коду.

Базовий синтаксис

@decorator_function  
def target_function():  
 pass

Синтаксис @decorator_function є скороченням для:

def target_function():  
 pass
target_function = decorator_function(target_function)

Як працюють декоратори

Декоратор — це, по суті, функція вищого порядку. Вона приймає функцію як вхідний параметр і повертає нову функцію. Давайте побудуємо один крок за кроком.

Приклад 1: Простіший декоратор

def my_decorator(func):  
 def wrapper():  
 print("Щось відбувається до виклику функції.")  
 func()  
 print("Щось відбувається після виклику функції.")  
 return wrapper
@my_decorator  
def say_hello():  
 print("Привіт, світ!")  
say_hello()

Виведення:

Щось відбувається до виклику функції.  
Привіт, світ!  
Щось відбувається після виклику функції.

Тут, my_decorator обгортає функцію say_hello і додає поведінку до та після її виконання.

Варіанти використання декораторів

1. Логування

Декоратори часто використовуються для логування викликів функцій та їхніх результатів.

def log_function_call(func):  
 def wrapper(*args, **kwargs):  
 print(f"Функція '{func.__name__}' була викликана з аргументами {args} та ключовими аргументами {kwargs}.")  
 result = func(*args, **kwargs)  
 print(f"Функція '{func.__name__}' повернула: {result}")  
 return result  
 return wrapper
@log_function_call  
def add(a, b):  
 return a + b  
add(5, 3)

Виведення:

Функція 'add' була викликана з аргументами (5, 3) та ключовими аргументами {}.  
Функція 'add' повернула: 8

2. Вимірювання часу виконання

Можна виміряти час виконання функції за допомогою декораторів.

import time  
def timing_function(func):  
 def wrapper(*args, **kwargs):  
 start_time = time.time()  
 result = func(*args, **kwargs)  
 end_time = time.time()  
 print(f"Функція '{func.__name__}' виконувалась {end_time - start_time:.4f} секунд.")  
 return result  
 return wrapper  
@timing_function  
def compute_square(numbers):  
 return [n ** 2 for n in numbers]  
compute_square(range(1, 100000))
**Виведення:**
Функція 'compute_square' виконувалась 0.0102 секунд.

3. Аутентифікація

Декоратори можуть забезпечити аутентифікацію користувачів або контроль доступу.

def authenticate_user(func):  
 def wrapper(user, *args, **kwargs):  
 if not user.get("is_authenticated"):  
 print("Користувач не аутентифікований!")  
 return  
 return func(user, *args, **kwargs)  
 return wrapper
@authenticate_user  
def view_dashboard(user):  
 print(f"Ласкаво просимо {user['username']} до панелі керування!")  
user1 = {"username": "John", "is_authenticated": True}  
user2 = {"username": "Doe", "is_authenticated": False}  
view_dashboard(user1)  
view_dashboard(user2)

Виведення:

Ласкаво просимо John до панелі керування!  
Користувач не аутентифікований!

4.

Логіка повторних спроб

Автоматично повторювати виклик функції, якщо вона не вдалася.

import random  

def retry_function(retries=3):  
 def decorator(func):  
 def wrapper(*args, **kwargs):  
 attempts = 0  
 while attempts < retries:  
 try:  
 return func(*args, **kwargs)  
 except Exception as e:  
 attempts += 1  
 print(f"Спроба {attempts} не вдалася: {e}")  
 print("Усі спроби не вдалися.")  
 return wrapper  
 return decorator  
@retry_function(retries=5)  
def flaky_function():  
 if random.random() < 0.7:  
 raise ValueError("Випадкова помилка!")  
 print("Функція виконана успішно!")  
flaky_function()
**Виведення:**
Спроба 1 не вдалася: Випадкова помилка!  
Спроба 2 не вдалася: Випадкова помилка!  
Функція виконана успішно!

Розширені декоратори

1. Декоратори з аргументами

Можна створювати декоратори, які самі приймають аргументи.

def repeat(n):  
 def decorator(func):  
 def wrapper(*args, **kwargs):  
 for _ in range(n):  
 func(*args, **kwargs)  
 return wrapper  
 return decorator
@repeat(3)  
def greet(name):  
 print(f"Привіт, {name}!")  
greet("Alice")

Виведення:

Привіт, Alice!  
Привіт, Alice!  
Привіт, Alice!

2. Ланцюгування декораторів

До однієї функції можна застосувати кілька декораторів.

def uppercase(func):  
 def wrapper(*args, **kwargs):  
 return func(*args, **kwargs).upper()  
 return wrapper
def exclaim(func):  
 def wrapper(*args, **kwargs):  
 return func(*args, **kwargs) + "!"  
 return wrapper  
@uppercase  
@exclaim  
def greet():  
 return "hello"  
print(greet())

Виведення:

HELLO!

Висновок

Декоратори Python — це потужний інструмент для розширення функціональності, покращення модульності та підвищення повторного використання коду. Від логування та вимірювання часу до аутентифікації та логіки повторних спроб — декоратори пропонують безліч можливостей для спрощення вашого коду. Оволодіння декораторами значно підвищить ваші навички розробки на Python.

Автор: СіваСантуш Вемпалі
Інженер-програміст з 4+ роками досвіду
Пристрасний до Python, розробки бекенду та масштабованих систем.

Перекладено з: Mastering Python Decorators: Simplify Your Code with This Powerful Tool

Leave a Reply

Your email address will not be published. Required fields are marked *