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

Как выполнить код до и после вызова функции в Python?

2.0 Middle🔥 231 комментариев
#Python Core

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

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

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

Как выполнить код до и после вызова функции?

Это делается через декораторы - один из самых мощных инструментов Python.

Простой пример декоратора

def my_decorator(func):
    def wrapper(*args, **kwargs):
        # КОД ДО вызова функции
        print("Перед вызовом функции")
        
        # Вызываем исходную функцию
        result = func(*args, **kwargs)
        
        # КОД ПОСЛЕ вызова функции
        print("После вызова функции")
        
        return result
    return wrapper

# Используем декоратор
@my_decorator
def greet(name):
    print(f"Hello, {name}!")

greet("John")
# Вывод:
# Перед вызовом функции
# Hello, John!
# После вызова функции

Пример 1: Логирование

import time
from functools import wraps

def log_calls(func):
    @wraps(func)  # Сохраняет имя функции
    def wrapper(*args, **kwargs):
        print(f"Вызова функции: {func.__name__}")
        print(f"Аргументы: {args}, {kwargs}")
        
        result = func(*args, **kwargs)
        
        print(f"Результат: {result}")
        return result
    return wrapper

@log_calls
def add(a, b):
    return a + b

add(5, 3)
# Вывод:
# Вызова функции: add
# Аргументы: (5, 3), {}
# Результат: 8

Пример 2: Измерение времени

import time
from functools import wraps

def measure_time(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        elapsed = time.time() - start
        
        print(f"{func.__name__} заняла {elapsed:.3f} сек")
        return result
    return wrapper

@measure_time
def slow_function():
    time.sleep(2)
    return "Done"

slow_function()
# Вывод:
# slow_function заняла 2.001 сек

Пример 3: Проверка прав доступа

from functools import wraps

def require_admin(func):
    @wraps(func)
    def wrapper(user, *args, **kwargs):
        if not user.is_admin:
            raise PermissionError("Нет доступа")
        
        return func(user, *args, **kwargs)
    return wrapper

@require_admin
def delete_user(user, user_id):
    print(f"Удаляю пользователя {user_id}")

delete_user(admin_user, 123)  # OK
delete_user(regular_user, 123)  # PermissionError

Пример 4: Кэширование результатов

from functools import wraps

def cache_result(func):
    cache = {}
    
    @wraps(func)
    def wrapper(*args, **kwargs):
        key = (args, tuple(kwargs.items()))
        
        if key in cache:
            print(f"Результат из кэша")
            return cache[key]
        
        result = func(*args, **kwargs)
        cache[key] = result
        return result
    
    return wrapper

@cache_result
def expensive_function(n):
    print(f"Вычисляю факториал {n}")
    return factorial(n)

expensive_function(5)  # Вычисляет
# Вывод: Вычисляю факториал 5

expensive_function(5)  # Из кэша
# Вывод: Результат из кэша

Пример 5: Обработка исключений

from functools import wraps

def handle_errors(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except ValueError as e:
            print(f"Ошибка значения: {e}")
            return None
        except Exception as e:
            print(f"Неожиданная ошибка: {e}")
            return None
    
    return wrapper

@handle_errors
def divide(a, b):
    return a / b

divide(10, 2)   # 5.0
divide(10, 0)   # Ошибка значения, возвращает None

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

from functools import wraps

def repeat(times):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            results = []
            for _ in range(times):
                result = func(*args, **kwargs)
                results.append(result)
            return results
        return wrapper
    return decorator

@repeat(3)
def hello():
    return "Hi"

hello()
# ["Hi", "Hi", "Hi"]

Стек декораторов

@log_calls
@measure_time
@cache_result
def complex_function(n):
    return n ** 2

# Декораторы применяются снизу вверх!
# Сначала cache_result, потом measure_time, потом log_calls

В FastAPI

from fastapi import FastAPI

app = FastAPI()

@app.get("/items/{item_id}")
def read_item(item_id: int):
    return {"item_id": item_id}

# @app.get - это декоратор!
# Он регистрирует функцию как endpoint

С контекстными менеджерами (альтернатива)

from contextlib import contextmanager

@contextmanager
def my_context():
    print("Вход")
    try:
        yield
    finally:
        print("Выход")

with my_context():
    print("Работа")

# Вывод:
# Вход
# Работа
# Выход

Класс-декоратор

class MyDecorator:
    def __init__(self, func):
        self.func = func
    
    def __call__(self, *args, **kwargs):
        print("Перед")
        result = self.func(*args, **kwargs)
        print("После")
        return result

@MyDecorator
def greet(name):
    print(f"Hello, {name}")

greet("John")

Итоговый вывод

Для выполнения кода до и после функции используй:

  1. Декораторы (функции)
  2. Декораторы (классы)
  3. Контекстные менеджеры

Декораторы - это мощный инструмент для:

  • Логирования
  • Измерения времени
  • Проверки прав
  • Кэширования
  • Обработки ошибок
  • И многого другого