【问题标题】:Accessing original decorated function for test purposes访问原始装饰函数以进行测试
【发布时间】:2013-02-03 05:40:46
【问题描述】:

我在视图函数中使用装饰器(@render_to 来自 django_annoying 包)。

但问题是我想获取视图函数返回的原始 dict 用于测试目的,而不是装饰器返回的 HttpResponse 对象。

装饰器使用@wraps(来自functools)。

如果无法访问它,那么您知道如何测试它吗?

【问题讨论】:

  • 我删除了django标签;这并不是 Django 特有的,真的。

标签: python testing decorator python-decorators introspection


【解决方案1】:

包装后的函数将作为函数闭包单元使用。哪个单元格具体取决于有多少闭包变量。

对于一个简单的包装器,其中唯一的闭包变量是要包装的函数,它将是第一个:

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

让内省变得简单一点。

【讨论】:

  • 在这里测试过,它工作正常!!感谢您提供详细而详细的答案 =) 和 python 3 信息。
【解决方案2】:

这是一个递归搜索在多个层次上装饰的原始函数的代码。 这背后的逻辑与@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)

【讨论】:

    猜你喜欢
    • 2016-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-25
    • 2015-08-18
    • 2011-09-22
    • 1970-01-01
    • 2011-12-20
    相关资源
    最近更新 更多