Как я могу украсить функцию Python без изменения имен аргументов?
Следующий код Python определяет регистратор и функцию факториала, а затем вызывает функцию факториала с аргументом ключевого слова:
def logger(f):
def f_(a):
print("Call", a)
return f(a)
return f_
# @logger # uncomment this line to see the problem
def factorial(n):
return 1 if n == 0 else n * factorial(n-1)
print(factorial(n=5))
в результате получается следующий результат (как и ожидалось): 120
,
Теперь, если я раскомментирую декоратор логгера, я получу ошибку, потому что имя аргумента стало a
вместо n
:
Как я могу украсить функцию (например, факториал) без изменения имен аргументов?
1 ответ
Решение
Игнорируя синтаксис декоратора, вот что вы делаете:
def logger(f):
def f_(a):
print("Call", a)
return f(a)
return f_
def factorial(n):
return 1 if n == 0 else n * factorial(n-1)
# `factorial` is `def f_(a):` now
factorial = logger(factorial)
Таким образом, чтобы просто исправить это, используйте ту же декларацию, или не используйте ключевые аргументы (n=5)
Лучший способ исправить это - использовать распаковку во внутренней функции:
import functools
def logger(f):
@functools.wraps(f)
def f_(*args, **kwargs):
print("Call", f.__name__, *args, *[f"{k}={v!r}" for k, v in kwargs.items()])
return f(*args, **kwargs)
return f_