我在使用一个装饰器(@render_to
来自 django_annoying
包)的视图函数中。
但问题是,我想得到view函数返回的原始dict,而不是用在测试上的 HttpResponse
对象,装饰器返回。
装饰器使用 @wraps
(自 functools
).
如果没有办法访问这个,那么你有什么办法可以测试这个吗?
封装后的函数将以函数闭包单元格的形式存在。具体是哪个单元格,取决于有多少个闭包变量。
对于一个简单的封装器,其中唯一的闭包变量是函数-to-wrap,它将是第一个。
wrapped = decorated.func_closure[0].cell_contents
但你可能需要检查所有的 func_closure
值。
>>> 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
让反省变得更加容易。
这里有一段代码,它可以递归搜索在多个层次上被装饰的原始函数.其背后的逻辑和@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)