假设我有一个如下定义的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模块来获得完整的源代码。你必须从inspect模块中使用getsource()方法。例如:

import inspect

def get_my_code():
    x = "abcd"
    return x

print(inspect.getsource(get_my_code))

你可以在下面的链接中查看更多选项。 检索python代码

总结一下:

import inspect
print( "".join(inspect.getsourcelines(foo)[0]))

如果源代码不可用,Dis是你的朋友:

>>> import dis
>>> def foo(arg1,arg2):
...     #do something with args
...     a = arg1 + arg2
...     return a
...
>>> dis.dis(foo)
  3           0 LOAD_FAST                0 (arg1)
              3 LOAD_FAST                1 (arg2)
              6 BINARY_ADD
              7 STORE_FAST               2 (a)

  4          10 LOAD_FAST                2 (a)
             13 RETURN_VALUE

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

如。

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

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

func.source = funcstring

扩展一下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。但是,当从源文件导入代码时,在这两种情况下都应该没问题。