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

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

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


当前回答

拉法łDowgird朋友与答案:

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

但是,可以检索从字符串编译的函数的源代码,前提是编译代码还向lineecache添加了一个条目。缓存dict类型:

import linecache
import inspect

script = '''
def add_nums(a, b):
    return a + b
'''

bytecode = compile(script, 'unique_filename', 'exec')
tmp = {}
eval(bytecode, {}, tmp)
add_nums = tmp["add_nums"]

linecache.cache['unique_filename'] = (
    len(script),
    None,
    script.splitlines(True),
    'unique_filename',
)

print(inspect.getsource(add_nums))

# prints:
# """
# def add_nums(a, b):
#    return a + b
# """

这就是attrs库如何自动为类创建各种方法,给定一组类期望初始化的属性。点击这里查看他们的源代码。正如源代码所解释的,这是一个主要用于使调试器(如PDB)能够逐级遍历代码的特性。

其他回答

inspect模块有从python对象中检索源代码的方法。但是,似乎只有当源文件位于文件中时,它才有效。如果你有这个,我猜你就不需要从对象中获取源了。


下面使用Python 3.6测试inspect.getsource(foo):

import inspect

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

source_foo = inspect.getsource(foo)  # foo is normal function
print(source_foo)

source_max = inspect.getsource(max)  # max is a built-in function
print(source_max)

这是第一次印刷:

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

然后在inspect.getsource(max)上失败,并出现以下错误:

TypeError: <built-in function max> is not a module, class, method, function, traceback, frame, or code object

虽然我通常同意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

>>> 

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

如。

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

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

func.source = funcstring

拉法łDowgird朋友与答案:

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

但是,可以检索从字符串编译的函数的源代码,前提是编译代码还向lineecache添加了一个条目。缓存dict类型:

import linecache
import inspect

script = '''
def add_nums(a, b):
    return a + b
'''

bytecode = compile(script, 'unique_filename', 'exec')
tmp = {}
eval(bytecode, {}, tmp)
add_nums = tmp["add_nums"]

linecache.cache['unique_filename'] = (
    len(script),
    None,
    script.splitlines(True),
    'unique_filename',
)

print(inspect.getsource(add_nums))

# prints:
# """
# def add_nums(a, b):
#    return a + b
# """

这就是attrs库如何自动为类创建各种方法,给定一组类期望初始化的属性。点击这里查看他们的源代码。正如源代码所解释的,这是一个主要用于使调试器(如PDB)能够逐级遍历代码的特性。

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

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