python - 如何获取装饰器包装的函数的源代码?

标签 python decorator python-2.x python-decorators

我想打印由 my_decorator 包装的 my_func 的源代码:

import inspect
from functools import wraps

def my_decorator(some_function):
    @wraps(some_function)
    def wrapper():
        some_function()

    return wrapper

@my_decorator
def my_func():
    print "supposed to return this instead!"
    return

print inspect.getsource(my_func)

但是,它返回包装器的源代码:

@wraps(some_function)
def wrapper():
    some_function()

有没有办法让它打印以下内容?

def my_func():
    print "supposed to return this instead!"
    return

请注意,以上内容是从一个更大的程序中抽象出来的。当然我们可以在这个例子中去掉装饰器,但这不是我想要的。

最佳答案

在 Python 2 中,@functools.wraps() 装饰器不设置方便的 __wrapped__ 属性,Python 3 version添加(Python 3.2 中的新功能)。

这意味着您将不得不求助于从闭包中提取原始函数。具体在什么位置将取决于具体的装饰器实现,但是选择第一个函数对象应该是一个很好的概括:

from types import FunctionType

def extract_wrapped(decorated):
    closure = (c.cell_contents for c in decorated.__closure__)
    return next((c for c in closure if isinstance(c, FunctionType)), None)

用法:

print inspect.getsource(extract_wrapped(my_func))

使用您的示例进行演示:

>>> print inspect.getsource(extract_wrapped(my_func))
@my_decorator
def my_func():
    print "supposed to return this instead!"
    return

另一种选择是更新 functools 库,为您添加一个 __wrapped__ 属性,就像 Python 3 一样:

import functools

def add_wrapped(uw):
    @functools.wraps(uw)
    def update_wrapper(wrapper, wrapped, **kwargs):
        wrapper = uw(wrapper, wrapped, **kwargs)
        wrapper.__wrapped__ = wrapped
        return wrapper

functools.update_wrapper = add_wrapped(functools.update_wrapper)

导入您希望看到受影响的装饰器之前运行该代码(因此他们最终使用新版本的functools.update_wrapper())。 您仍然必须手动解包(Python 2 inspect 模块不去寻找属性);这是一个简单的辅助函数:

def unwrap(func):
    while hasattr(func, '__wrapped__'):
        func = func.__wrapped__
    return func

这将打开任何级别的装饰器包装。或者使用 inspect.unwrap() implementation from Python 3 的副本,其中包括检查意外循环引用。

关于python - 如何获取装饰器包装的函数的源代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43506378/

相关文章:

python - python 中可扩展返回对象的最佳方法

pandas - 基于掩码的前向填充数据帧。填写最后一个有效值

python - 如何从任何用户的推特获取 'n' 推文

python - listdir 不能正确打印非英文字母

Python XML Feed 解析器无法找到特定事件

python - 如何从数据框中创建多个附加列并添加到同一数据框中

Python Appengine 在执行 app.yaml 之前运行某些代码

python:装饰器名称应该是 Action 还是描述?

java - Decorator方法,Java中的一种Decorator类型

python - 用装饰器类装饰的方法没有卡住 "self"参数