我想获取Python函数的源代码。但是,我正在处理的函数具有使用函数本身实例化的装饰器。似乎inspect
或dill
有问题。特别是,我尝试了以下MWE:
class Decorator(object):
def __init__(self, item):
self.item = item
self.func = None
def __call__(self, func):
self.func = func
return self
@Decorator(42)
def fun_1():
pass
@Decorator(lambda x: 42)
def fun_2():
pass
@Decorator(fun_2.item)
def fun_3():
pass
import inspect
print("Inspect results")
print(inspect.getsource(fun_1.func))
print(inspect.getsource(fun_2.func))
print(inspect.getsource(fun_3.func))
import dill
print("Dill results")
print(dill.source.getsource(fun_1.func))
print(dill.source.getsource(fun_2.func))
print(dill.source.getsource(fun_3.func))
对于函数fun_1
和fun_3
,这会给出预期的结果。对于fun_2
(尽管它与fun_3基本相同),inspect
或dill
返回的源代码是错误的 - 它只给我装饰线。我希望得到
@Decorator(lambda x: 42)
def fun_2():
pass
但我得到的只是
@Decorator(lambda x: 42)
我可以想象两个模块只搜索第一个函数声明。这个假设是否正确,除了重新实现inspect
或dill
之外还有一个好的解决方法吗?
编辑:我使用的是Python 2.7,但使用Python 3.4时遇到了相同的行为。
答案 0 :(得分:2)
我是dill
作者。我认为你在inspect
中发现了一个错误,关于在装饰器中解析包含lambda
作为参数的代码块。
>>> f = lambda x: 42
>>> @Decorator(f)
... def fun_4():
... pass
...
>>>
>>> print dill.source.getsource(fun_4.func)
@Decorator(f)
def fun_4():
pass
>>>
请注意,只需使用指向lambda
对象的指针即可。这就是你的解决方法。
我认为这个角落案例是inspect
中的一个错误,dill
正在使用它...所以这也是dill
中的错误。
我已在dill
GitHub页面上打开了一张票,我将进一步调查以查看(1)是否有可在dill
中实施的简单解决方法,以及(2) )如果它确实是inspect
中的一个错误(我猜它是) - 如果是这样的话,它应该填充给python开发人员。这是该票证的链接:https://github.com/uqfoundation/dill/issues/221