def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("До вызова функции.")
        result = func(*args, **kwargs)
        print("После вызова функции.")
        return result
    return wrapper
def func1():
    print("Функция 1")
def func2():
    print("Функция 2")
func1 = my_decorator(func1)
func2 = my_decorator(func2)
      
def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("До вызова функции.")
        result = func(*args, **kwargs)
        print("После вызова функции.")
        return result
    return wrapper
def func1():
    print("Функция 1")
def func2():
    print("Функция 2")
functions = [func1, func2]
for i, func in enumerate(functions):
    functions[i] = my_decorator(func)
      
def apply_decorator_to_functions(decorator):
    def apply(functions):
        for i, func in enumerate(functions):
            functions[i] = decorator(func)
        return functions
    return apply
def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("До вызова функции.")
        result = func(*args, **kwargs)
        print("После вызова функции.")
        return result
    return wrapper
def func1():
    print("Функция 1")
def func2():
    print("Функция 2")
apply_my_decorator = apply_decorator_to_functions(my_decorator)
funcs = apply_my_decorator([func1, func2])
# Теперь func1 и func2 задекорированы (но не перезаписаны в глобальной области видимости)
      Есть несколько способов применить один и тот же декоратор к нескольким функциям в Python. Важно понимать, что "одновременно" в данном контексте обычно означает избежать повторения кода декоратора для каждой функции вручную. Вот несколько подходов:
1. Применение декоратора непосредственно к нескольким функциям подряд:
    
def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("Выполняется код до функции.")
        result = func(*args, **kwargs)
        print("Выполняется код после функции.")
        return result
    return wrapper
@my_decorator
def function_one():
    print("Функция первая")
@my_decorator
def function_two():
    print("Функция вторая")
function_one()
function_two()
    
  
  Это самый простой и очевидный способ.  Мы просто ставим @my_decorator над каждой функцией, которую хотим декорировать.  Этот подход хорошо работает, если функций немного.
2. Использование цикла (при определенных обстоятельствах):
Этот метод применим, когда функции хранятся в списке или другой итерируемой структуре. Не всегда возможно или желательно так делать, но иногда это полезно:
    
def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("Выполняется код до функции.")
        result = func(*args, **kwargs)
        print("Выполняется код после функции.")
        return result
    return wrapper
def function_one():
    print("Функция первая")
def function_two():
    print("Функция вторая")
functions = [function_one, function_two]
for i in range(len(functions)):
    functions[i] = my_decorator(functions[i])
function_one()
function_two()
    
  
  Обратите внимание, что в этом случае мы присваиваем результат декорирования обратно элементам списка. Это изменяет исходный список функций. Также крайне важно выполнять это *вне* определения самих функций. Изменение глобальной области видимости внутри определения может привести к неожиданным результатам.
3. Создание класса-декоратора:
Классы-декораторы позволяют создавать более сложные декораторы, которые могут сохранять состояние или иметь параметризацию.  Хотя они не обязательно упрощают применение к нескольким функциям одновременно, они обеспечивают лучшую организацию кода, особенно для сложных сценариев.  Синтаксис применения остается тем же: @MyClassDecorator.
    
class MyDecorator:
    def __init__(self, message):
        self.message = message
    def __call__(self, func):
        def wrapper(*args, **kwargs):
            print(f"Сообщение декоратора: {self.message}")
            result = func(*args, **kwargs)
            return result
        return wrapper
@MyDecorator("Привет от декоратора!")
def my_function():
    print("Функция выполняется.")
my_function()
    
  
  4. (Продвинутый) Создание функции для группового декорирования:
Можно создать функцию, которая принимает декоратор и список функций и применяет декоратор ко всем функциям в списке:
    
def decorate_multiple(decorator, functions):
    for func in functions:
        globals()[func.__name__] = decorator(func)  # Модифицирует глобальную область видимости
def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("Код до функции")
        result = func(*args, **kwargs)
        print("Код после функции")
        return result
    return wrapper
def function_one():
    print("Функция первая")
def function_two():
    print("Функция вторая")
functions_to_decorate = [function_one, function_two]
decorate_multiple(my_decorator, functions_to_decorate)
function_one()
function_two()
    
  
  Внимание! Этот метод использует globals() для изменения глобальной области видимости. Это может быть небезопасным и не рекомендуется в большинстве случаев, особенно в больших проектах, так как затрудняет отладку и понимание кода. Лучше избегать изменения глобальной области видимости таким образом.
5. (Продвинутый) Использование метаклассов:
Этот подход значительно более сложный и используется реже. Он предполагает создание метакласса, который автоматически применяет декоратор ко всем функциям, определенным в классе. Это может быть полезно, если у вас есть много методов в классе, которые нужно декорировать одинаково.
В заключение, самый простой и распространенный способ – просто применить декоратор непосредственно к каждой функции, используя синтаксис @decorator_name. Более сложные подходы, такие как использование циклов или функций для группового декорирования, следует использовать с осторожностью и только тогда, когда это действительно необходимо, чтобы избежать усложнения кода и потенциальных проблем с областью видимости.