假设我有一个如下定义的Python函数:

def foo(arg1,arg2):
    #do something with args
    a = arg1 + arg2
    return a

我可以使用foo.func_name获取函数的名称。我如何通过编程获得它的源代码,就像我上面键入的那样?


当前回答

请注意,只有在单独的一行上给出lambda时,接受的答案才有效。如果您将它作为参数传递给一个函数,并希望检索lambda作为对象的代码,那么问题就会变得有点棘手,因为inspect会给您整行代码。

例如,考虑一个文件test.py:

import inspect

def main():
    x, f = 3, lambda a: a + 1
    print(inspect.getsource(f))

if __name__ == "__main__":
    main()

执行它会给你(注意缩进!):

    x, f = 3, lambda a: a + 1

在我看来,要检索lambda的源代码,最好的方法是重新解析整个源文件(通过使用f.__code__.co_filename),并根据行号及其上下文匹配lambda AST节点。

我们必须在契约式设计库契约中做到这一点,因为我们必须解析作为参数传递给装饰器的lambda函数。这里粘贴的代码太多了,所以看一下这个函数的实现。

其他回答

虽然我通常同意inspect是一个很好的答案,但我不同意您不能获得解释器中定义的对象的源代码。如果从dill中使用dill.source.getsource,则可以获得函数和lambda的源,即使它们是以交互方式定义的。 它还可以从在curry中定义的绑定或未绑定类方法和函数中获取代码…但是,如果没有封闭对象的代码,则可能无法编译该代码。

>>> from dill.source import getsource
>>> 
>>> def add(x,y):
...   return x+y
... 
>>> squared = lambda x:x**2
>>> 
>>> print getsource(add)
def add(x,y):
  return x+y

>>> print getsource(squared)
squared = lambda x:x**2

>>> 
>>> class Foo(object):
...   def bar(self, x):
...     return x*x+x
... 
>>> f = Foo()
>>> 
>>> print getsource(f.bar)
def bar(self, x):
    return x*x+x

>>> 

由于这篇文章被标记为另一篇文章的副本,我在这里回答“lambda”情况,尽管OP不是关于lambdas的。

因此,对于没有在自己的行中定义的lambda函数:除了marko。在ristin的回答中,您可能希望使用mini-lambda或使用此回答中建议的SymPy。

Mini-lambda更轻,支持任何类型的操作,但只适用于单个变量 SymPy更重,但配备了更多的数学/微积分运算。特别是它可以简化你的表达。它还支持同一个表达式中的多个变量。

下面是使用mini-lambda的方法:

from mini_lambda import x, is_mini_lambda_expr
import inspect

def get_source_code_str(f):
    if is_mini_lambda_expr(f):
        return f.to_string()
    else:
        return inspect.getsource(f)

# test it

def foo(arg1, arg2):
    # do something with args
    a = arg1 + arg2
    return a

print(get_source_code_str(foo))
print(get_source_code_str(x ** 2))

它会正确地产生

def foo(arg1, arg2):
    # do something with args
    a = arg1 + arg2
    return a

x ** 2

详见mini-lambda文档。顺便说一下,我是作者;)

扩展一下runeh的回答:

>>> def foo(a):
...    x = 2
...    return x + a

>>> import inspect

>>> inspect.getsource(foo)
u'def foo(a):\n    x = 2\n    return x + a\n'

print inspect.getsource(foo)
def foo(a):
   x = 2
   return x + a

编辑:正如@0sh指出的那样,这个例子使用ipython工作,而不是纯python。但是,当从源文件导入代码时,在这两种情况下都应该没问题。

如果您自己严格地定义了函数,并且它是一个相对较短的定义,那么没有依赖关系的解决方案将是在字符串中定义函数,并将表达式的eval()赋值给您的函数。

如。

funcstring = 'lambda x: x> 5'
func = eval(funcstring)

然后可选地将原始代码附加到函数:

func.source = funcstring

如果函数来自文件系统中可用的源文件,那么inspect.getsource(foo)可能会有帮助:

如果foo被定义为:

def foo(arg1,arg2):         
    #do something with args 
    a = arg1 + arg2         
    return a  

然后:

import inspect
lines = inspect.getsource(foo)
print(lines)

返回:

def foo(arg1,arg2):         
    #do something with args 
    a = arg1 + arg2         
    return a                

但我相信,如果函数是从字符串、流或从编译文件导入的,那么你就不能检索它的源代码。