Как я могу украсить функцию Python без изменения имен аргументов? - PullRequest
0 голосов
/ 28 ноября 2018

Следующий код 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 Ответ

0 голосов
/ 28 ноября 2018

Игнорирование синтаксиса декоратора, вот что вы делаете:

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_

Вот полезная статья по теме.

...