如何获取装饰器包装的函数的源代码? [英] How to get source code of function that is wrapped by a decorator?
问题描述
我想打印 my_func
的源代码,该源代码由 my_decorator
包装:
I wanted to print the source code for my_func
, that is wrapped by my_decorator
:
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)
但是,而是返回包装器的源代码:
However, it returns source for wrapper instead:
@wraps(some_function)
def wrapper():
some_function()
有没有办法打印以下内容?
Is there a way for it to print the following instead?
def my_func():
print "supposed to return this instead!"
return
请注意,以上内容是从较大的程序中抽象出来的。当然,在这个示例中我们可以摆脱装饰器,但这不是我想要的。
Note that the above is abstracted from a larger program. Of course we can just get rid of the decorator in this example, but that's not what I am looking for.
推荐答案
在Python 2中, @ functools.wraps()
装饰器没有设置__wrapped __ 属性= noreferrer> Python 3版本添加了(Python 3.2中的新功能)。
In Python 2, the @functools.wraps()
decorator does not set the convenience __wrapped__
attribute that the Python 3 version adds (new in Python 3.2).
这意味着您必须求助于提取原始函数从结束处开始。确切的位置将取决于确切的装饰器实现,但是选择第一个函数对象应该是一个很好的概括:
This means you'll have to resort to extracting the original function from the closure. Exactly at what location will depend on the exact decorator implementation, but picking the first function object should be a good generalisation:
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一样:
Another option is to update the functools
library to add a __wrapped__
attribute for you, the same way Python 3 does:
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
模块不会寻找该属性);这是一个简单的辅助函数:
Run that code before importing the decorator you want to see affected (so they end up using the new version of functools.update_wrapper()
).
You'll have to manually unwrap still (the Python 2 inspect
module doesn't go looking for the attribute); here's a simple helper function do that:
def unwrap(func):
while hasattr(func, '__wrapped__'):
func = func.__wrapped__
return func
这将解开任何内容装饰包装的水平。或使用 inspect.unwrap()
实现,其中包括检查意外的循环引用。
This will unwrap any level of decorator wrapping. Or use a copy of the inspect.unwrap()
implementation from Python 3, which includes checking for accidental circular references.
这篇关于如何获取装饰器包装的函数的源代码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!