访问原始的装饰函数以进行测试目的

4
我在一个视图函数中使用了装饰器(来自django_annoying包的@render_to)。但问题是,我想要获取视图函数返回的原始字典以进行测试,而不是装饰器返回的HttpResponse对象。该装饰器使用functools中的@wraps。如果无法访问它,那么你有任何测试它的想法吗?

2
我删除了 django 标签;这与 Django 没有关系,实际上。 - Martijn Pieters
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

让内省变得更加容易。


已在此处测试,它正常工作!感谢您提供良好且详细的答案 =)以及有关Python 3的信息。 - Arruda

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)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接