Функция, оформленная с помощью functools.wraps, вызывает TypeError с именем оболочки. Почему? Как избежать?

def decorated(f):
    @functools.wraps(f)
    def wrapper():
        return f()
    return wrapper

@decorated
def g():
    pass

functools.wraps выполняет свою работу по сохранению имени g:

>>> g.__name__
'g'

Но если я передам аргумент g, я получу TypeError, содержащее имя оболочки:

>>> g(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: wrapper() takes no arguments (1 given)

Откуда это имя? Где он сохраняется? И есть ли способ сделать исключение похожим на g() takes no arguments?


person jacquev6    schedule 28.04.2015    source источник
comment
Связано: stackoverflow.com/q/29488327/3001761   -  person jonrsharpe    schedule 28.04.2015


Ответы (1)


Имя происходит от объекта кода; и функция, и объект кода (содержащий, среди прочего, исполняемый байт-код) содержат это имя:

>>> g.__name__
'g'
>>> g.__code__.co_name
'wrapper'

Атрибут объекта кода доступен только для чтения:

>>> g.__code__.co_name = 'g'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: readonly attribute

Вам нужно будет создать совершенно новый объект кода, чтобы переименовать его, см. мой предыдущий ответ, где я определил функцию для этого; используя функцию rename_code_object() в вашей оформленной функции:

>>> g = rename_code_object(g, 'g')
>>> g(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: g() takes no arguments (1 given)

Обратите внимание, однако, что это полностью скроет, какой код выполнялся! Обычно вы хотите видеть, что была задействована оболочка декоратора; в конце концов, именно оболочка выдает исключение, а не исходная функция.

person Martijn Pieters    schedule 28.04.2015
comment
Действительно, я только что связался с другим вашим ответом, где вы показываете, как это сделать! После g = rename_code_object(g, 'g') сообщение об ошибке становится TypeError: g() takes no arguments (1 given) по желанию. - person jonrsharpe; 28.04.2015