我在视图函数中使用了装饰器(@render_to
包中的django_annoying
)。
但问题是我想获取视图函数返回的原始dict用于测试目的,而不是装饰器返回的HttpResponse
对象。
装饰者使用@wraps
(来自functools
)。
如果无法访问此内容,那么您是否知道如何测试?
答案 0 :(得分:8)
包装函数将作为函数闭包单元格提供。哪个单元格完全取决于有多少个闭包变量。
对于一个简单的包装器,其中唯一的闭包变量是函数包装,它将是第一个:
wrapped = decorated.func_closure[0].cell_contents
但您可能需要检查所有func_closure
值。
使用functools.wraps()
example decorator进行演示:
>>> 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
看source code for @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
让内省更容易一点。
答案 1 :(得分: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)