← Назад к вопросам

Что такое декораторы в Python?

1.0 Junior🔥 161 комментариев
#Python

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое декораторы в Python?

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

Декораторы основаны на концепции higher-order functions (функции, которые работают с функциями как с объектами данных).

Базовая концепция

В Python функции — это объекты первого класса, их можно:

  • Передавать как аргументы
  • Возвращать из других функций
  • Присваивать переменным
  • Хранить в структурах данных
# Функция как объект
def greet():
    return "Hello"

# Присвоить переменной
greeting = greet
print(greeting())  # Output: Hello

# Передать как аргумент
def execute(func):
    return func()

print(execute(greet))  # Output: Hello

Как работают декораторы

# Простой декоратор
def my_decorator(func):
    def wrapper(*args, **kwargs):
        print(f"Функция {func.__name__} начала выполнение")
        result = func(*args, **kwargs)
        print(f"Функция {func.__name__} завершила выполнение")
        return result
    return wrapper

# Применение декоратора
@my_decorator
def say_hello(name):
    return f"Hello, {name}!"

# Эквивалентно:
# say_hello = my_decorator(say_hello)

print(say_hello("Alice"))

Вывод:

Функция say_hello начала выполнение
Hello, Alice!
Функция say_hello завершила выполнение

Практические примеры для Data Engineer

1. Логирование времени выполнения (profiling)

import time
from functools import wraps

def timing_decorator(func):
    @wraps(func)  # сохраняет оригинальные метаданные функции
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        elapsed = time.time() - start_time
        print(f"{func.__name__} took {elapsed:.2f} seconds")
        return result
    return wrapper

@timing_decorator
def process_large_dataset(df):
    # долгая операция
    return df.groupby(category).sum()

process_large_dataset(data)  # Output: process_large_dataset took 2.34 seconds

2. Retry механизм для API запросов

import time
from functools import wraps

def retry(max_attempts=3, delay=2):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            for attempt in range(max_attempts):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    if attempt == max_attempts - 1:
                        raise
                    print(f"Attempt {attempt + 1} failed, retrying in {delay}s...")
                    time.sleep(delay)
        return wrapper
    return decorator

@retry(max_attempts=3, delay=2)
def fetch_data_from_api(url):
    # может выбросить исключение
    response = requests.get(url)
    return response.json()

3. Кэширование результатов (memoization)

from functools import lru_cache

@lru_cache(maxsize=128)
def expensive_computation(n):
    # долгая операция
    return sum(range(n))

print(expensive_computation(1000))  # вычисляет
print(expensive_computation(1000))  # возвращает из кэша

4. Валидация аргументов

from functools import wraps

def validate_args(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        # проверяем, что все аргументы положительные
        for arg in args:
            if isinstance(arg, (int, float)) and arg < 0:
                raise ValueError(f"Negative argument: {arg}")
        return func(*args, **kwargs)
    return wrapper

@validate_args
def calculate_percentage(total, part):
    return (part / total) * 100

print(calculate_percentage(100, 25))  # Output: 25.0
print(calculate_percentage(100, -25))  # Raises ValueError

5. Декоратор для преобразования результата

from functools import wraps
import json

def json_response(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return json.dumps(result, indent=2)
    return wrapper

@json_response
def get_user_info():
    return {"id": 1, "name": "Alice", "email": "alice@example.com"}

print(get_user_info())

Декораторы с параметрами

Декоратор может сам принимать параметры (требуется дополнительный уровень функций):

from functools import wraps

def repeat(times):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            for i in range(times):
                print(f"Execution {i + 1}")
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(times=3)
def greet(name):
    print(f"Hello, {name}!")

greet("Bob")

Вывод:

Execution 1
Hello, Bob!
Execution 2
Hello, Bob!
Execution 3
Hello, Bob!

Декораторы классов

Декораторы работают и с классами:

from functools import wraps

def add_repr(cls):
    original_repr = cls.__repr__
    def new_repr(self):
        return f"{cls.__name__}({self.__dict__})"
    cls.__repr__ = new_repr
    return cls

@add_repr
class User:
    def __init__(self, name, age):
        self.name = name
        self.age = age

user = User("Alice", 30)
print(user)  # Output: User({name: Alice, age: 30})

Встроенные декораторы Python

  • @property — превращает метод в атрибут
  • @staticmethod — статический метод класса
  • @classmethod — метод класса
  • @functools.wraps — сохраняет метаданные функции
  • @functools.lru_cache — кэширование результатов
  • @functools.singledispatch — полиморфизм на основе типа

Ключевые преимущества

  • Переиспользование кода — декоратор применяется к многим функциям
  • Разделение ответственности — логика добавляется отдельно от основного кода
  • Улучшение читаемости — синтаксис @ делает явным, что функция модифицирована
  • Гибкость — можно комбинировать несколько декораторов

Множественные декораторы

@timing_decorator
@retry(max_attempts=3)
@validate_args
def process_data(filename):
    # код...
    pass

# Применяются в обратном порядке (от низа к верхe)
# 1. validate_args
# 2. retry
# 3. timing_decorator
Что такое декораторы в Python? | PrepBro