Сообщить об ошибке.

Захват параметров декорируемой функцией

Например, есть функция, которая принимает аргументы и простой декоратор. Попробуем применить декоратор к функции с параметрами:

def sample_decorator(func):
    def wrapper():
        dash = '-'*15
        print(dash)
        func()
        print(dash)
    return wrapper

@sample_decorator
def say(name):
    print('Привет {name}.')
    
>>> say('Андрей')
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# TypeError: wrapper() takes 0 positional arguments but 1 was given

При выполнении этого кода возникает ошибка. Проблема в том, что внутренняя функция wrapper() не принимает никаких аргументов, а мы пытались ей передать один аргумент name. Эту проблему можно исправить, позволив wrapper() принять один аргумент, но тогда она не будет работать для функций, которые не принимают аргументов или принимают больше одного аргумента.

Решение заключается в использовании *args и **kwargs во внутренней функции wrapper() декоратора. Тогда она будет принимать произвольное число позиционных и ключевых аргументов. Перепишем декоратор с использованием *args и **kwargs в функции обертке wrapper(), а так же будем передавать произвольное число позиционных и ключевых аргументов функции func(), которую декоратор получает в качестве аргумента:

def sample_decorator(func):
    def wrapper(*args, **kwargs):
        dash = '-'*15
        print(dash)
        func(*args, **kwargs)
        print(dash)
    return wrapper

@sample_decorator
def say(name):
    print('Привет {name}.')
    
>>> say('Андрей')
# ---------------
# Привет Андрей.
# ---------------

В примере выше, вложенная функция wrapper() принимает любое количество аргументов и передает их в декорируемую функцию func(). Теперь декоратор @sample_decorator будет работать как для функций, которые вообще не принимают аргументы, так и для функций которые принимают произвольное количество аргументов.