Справочник Python

Полное руководство по языку на русском

Декораторы и замыкания

Декораторы функций

import functools  # импорт модуля
import time  # импорт модуля времени

def timer(func):
    @functools.wraps(func)  # сохранение метаданных декорируемой функции
    def wrapper(*args, **kwargs):
        start = time.time()  # метка времени в секундах
        result = func(*args, **kwargs)  # присваивание
        elapsed = time.time() - start  # метка времени в секундах
        print(f"{func.__name__} заняла {elapsed:.3f}s")  # вывод в консоль
        return result  # возврат значения
    return wrapper  # возврат значения

@timer
def slow_add(a, b):
    """Складывает два числа."""
    time.sleep(0.5)  # пауза
    return a + b  # возврат значения

slow_add(1, 2)  # slow_add заняла 0.501s
print(slow_add.__name__)  # slow_add (без wraps было бы 'wrapper')

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

def repeat(n):
    def decorator(func):
        @functools.wraps(func)  # сохранение метаданных декорируемой функции
        def wrapper(*args, **kwargs):
            for _ in range(n):  # цикл по элементам
                result = func(*args, **kwargs)  # присваивание
            return result  # возврат значения
        return wrapper  # возврат значения
    return decorator  # возврат значения

@repeat(3)
def say(message):
    print(message)  # вывод в консоль

say("Привет!")

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

def add_repr(cls):
    def __repr__(self):
        items = ", ".join(f"{k}={v}" for k, v in self.__dict__.items())  # получение пар ключ-значение
        return f"{cls.__name__}({items})"  # возврат значения
    cls.__repr__ = __repr__
    return cls  # возврат значения

@add_repr
class User:
    def __init__(self, name, age):
        self.name = name  # обращение к атрибуту экземпляра
        self.age = age  # обращение к атрибуту экземпляра

user = User("Анна", 30)  # присваивание
print(user)  # User(name=Анна, age=30)

Декоратор для методов класса

def log_call(method):
    @functools.wraps(method)  # сохранение метаданных декорируемой функции
    def wrapper(self, *args, **kwargs):
        print(f"Вызов {method.__name__}")  # вывод в консоль
        return method(self, *args, **kwargs)  # возврат значения
    return wrapper  # возврат значения

class Service:
    @log_call
    def process(self, data):
        return f"Обработка: {data}"  # возврат значения

Замыкания (closures)

def multiplier(factor):
    def multiply(x):
        return x * factor  # возврат значения
    return multiply  # возврат значения

double = multiplier(2)  # присваивание
triple = multiplier(3)  # присваивание
print(double(5))  # 10
print(triple(5))  # 15

functools.partial — частичное применение

from functools import partial  # импорт модуля

def power(base, exp):
    return base ** exp  # возврат значения

square = partial(power, exp=2)  # присваивание
cube = partial(power, exp=3)  # присваивание

print(square(5))  # 25
print(cube(5))    # 125