我在一个视图函数中使用了装饰器(来自django_annoying包的@render_to)。但问题是,我想要获取视图函数返回的原始字典以进行测试,而不是装饰器返回的HttpResponse对象。该装饰器使用functools中的@wraps。如果无法访问它,那么你有任何测试它的想法吗?
包装函数将作为函数闭包单元格可用。确切的单元格取决于闭包变量的数量。
对于一个简单的封装器,其中唯一的闭包变量是要封装的函数,它将是第一个:
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
让内省变得更加容易。
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)
django
标签;这与 Django 没有关系,实际上。 - Martijn Pieters