4

ビュー関数でデコレータ(パッケージ@render_toから)を使用しています。django_annoying

HttpResponseしかし、問題は、デコレータが返すオブジェクトではなく、テスト目的でビュー関数によって返される元の dict を取得したかったことです。

デコレータは@wraps(from functools) を使用します。

これにアクセスする方法がない場合、これをテストする方法はありますか?

4

2 に答える 2

13

ラップされた関数は、関数クロージャ セルとして使用できます。どのセルが正確には、クロージャ変数がいくつあるかによって異なります。

唯一のクロージャ変数がラップする関数である単純なラッパーの場合、それは最初のものになります:

wrapped = decorated.func_closure[0].cell_contents

ただし、すべての値を検査する必要がある場合がありfunc_closureます。

functools.wraps()サンプル デコレータを使用したデモ:

>>> from functools import wraps
>>> def my_decorator(f):
...     @wraps(f)
...     def wrapper(*args, **kwds):
...         print 'Calling decorated function'
...         return f(*args, **kwds)
...     return wrapper
... 
>>> @my_decorator
... def example():
...     """Docstring"""
...     print 'Called example function'
... 
>>> example
<function example at 0x107ddfaa0>
>>> example.func_closure
(<cell at 0x107de3d70: function object at 0x107dc3b18>,)
>>> example.func_closure[0].cell_contents
<function example at 0x107dc3b18>
>>> example()
Calling decorated function
Called example function
>>> example.func_closure[0].cell_contents()
Called example function

ただし、ソース コードを@render_to見ても、これについて心配する必要はありません。ラップされた関数は、保証された最初のクロージャ スロットに格納されます。

これが代わりに Python 3 であった場合、代わりに__wrapped__属性を使用してラップされた関数にアクセスできます。

>>> example.__wrapped__
<function example at 0x103329050>

また、デコレータ コード自体にアクセスできる場合は、同じ参照を Python 2 コードにも簡単に追加できます。

def my_decorator(f):
    @wraps(f)
    def wrapper(*args, **kwds):
        # implementation

    wrapper.__wrapped__ = f
    return wrapper

イントロスペクションを少しだけ簡単にします。

于 2013-02-18T17:59:57.200 に答える
0

これは、多くのレベルで装飾された元の関数を再帰的に検索するコードです。この背後にあるロジックは、@Martin が言及した回答と同じです

def get_original_decorated_function(deco_func, org_func_name= None):
    if not deco_func.func_closure:
        if deco_func.__name__ == org_func_name:
            return deco_func
        else:
            return None
    for closure in deco_func.func_closure:
        func = closure.cell_contents
        if func.__name__ == org_func_name:
            # This is the original function name
            return func
        else:
            # Recursively call the intermediate function
            return get_original_decorated_function(func, org_func_name)
于 2020-04-29T05:14:47.760 に答える