如何获取Python函数的源代码?

时间:2009-01-09 09:02:38

标签: python function

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

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

我可以使用foo.func_name获取该函数的名称。我如何以编程方式获取其源代码,如上面输入的那样?

13 个答案:

答案 0 :(得分:462)

如果该函数来自文件系统上可用的源文件,那么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                

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

答案 1 :(得分:176)

inspect module具有从python对象检索源代码的方法。看起来它只有在源位于文件中时才有效。如果你有,我想你不需要从对象获取源。

答案 2 :(得分:79)

如果源代码不可用,

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

答案 3 :(得分:64)

如果您使用的是IPython,则需要输入“foo ??”

In [19]: foo??
Signature: foo(arg1, arg2)
Source:
def foo(arg1,arg2):
    #do something with args
    a = arg1 + arg2
    return a

File:      ~/Desktop/<ipython-input-18-3174e3126506>
Type:      function

答案 4 :(得分:55)

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

>>> 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

>>> 

答案 5 :(得分:21)

扩展符文的回答:

>>> 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。但是,从源文件导入代码时,两者都应该没问题。

答案 6 :(得分:10)

您可以使用inspect模块获取完整的源代码。您必须使用getsource()模块中的inspect方法。例如:

import inspect

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

print(inspect.getsource(get_my_code))

您可以在以下链接中查看更多选项。 retrieve your python code

答案 7 :(得分:4)

总结:

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

答案 8 :(得分:3)

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

E.g。

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

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

func.source = funcstring

答案 9 :(得分:2)

请注意,只有当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节点。上下文。

我们必须在按合同设计的库icontract中做到这一点,因为我们必须解析作为装饰器参数传入的lambda函数。在此处粘贴的代码太多,因此请查看the implementation of this function

答案 10 :(得分:1)

由于此帖子被标记为this other post的重复,因此我在这里回答“ lambda”的情况,尽管操作与lambda无关。

因此,对于未在其自己的行中定义的lambda函数:除了marko.ristin的答案之外,您可能希望使用mini-lambda或使用SymPy,如{ {3}}。

  • 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 this answer。我是作者;)

答案 11 :(得分:0)

相信变量名称未存储在pyc / pyd / pyo文件中,因此如果您没有源文件,则无法检索确切的代码行。

答案 12 :(得分:0)

如果使用IPython,另一种选择是在函数名称后使用??以查看其源代码。这是一个示例:

[nav] In [1]: def foo(arg1,arg2):
         ...:     #do something with args
         ...:     a = arg1 + arg2
         ...:     return a

[nav] In [2]: foo??
Signature: foo(arg1, arg2)
Docstring: <no docstring>
Source:
def foo(arg1,arg2):
    #do something with args
    a = arg1 + arg2
    return a