12
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か?

4

2 に答える 2

10

名前はコード オブジェクトに由来します。関数とコード オブジェクト (特に実行されるバイトコードを含む) の両方にその名前が含まれます。

>>> 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)

ただし、これにより、実行中のコードが完全にマスクされることに注意してください。通常、デコレータ ラッパーが関与していることを確認する必要があります。結局のところ、元の関数ではなく、例外をスローするのはラッパーです。

于 2015-04-28T12:47:37.110 に答える
1

Martijn の回答は最初の 2 つの質問をカバーしていますが、より良い解決策がありfます。wrapper()f()

import functools

def decorated(f):
    @functools.wraps(f)
    def wrapper(*args, **kwargs):  # <- Take any arguments
        return f(*args, **kwargs)  # <- Forward
    return wrapper

@decorated
def g():
    pass

g(1)

出力:

Traceback (most recent call last):
  File "/home/wja/testdir/tmp.py", line 15, in <module>
    g(1)
  File "/home/wja/testdir/tmp.py", line 8, in wrapper
    return f(*args, **kwargs)
TypeError: g() takes 0 positional arguments but 1 was given
于 2021-11-02T17:58:50.443 に答える