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

2024-12-02 08:41:00
admin
原创
168
摘要:问题描述:假设我有一个如下定义的 Python 函数:def foo(arg1,arg2): #do something with args a = arg1 + arg2 return a 我可以使用 获取函数的名称foo.func_name。如何以编程方式获取其源代码,如我上面输入...

问题描述:

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

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

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


解决方案 1:

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

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

解决方案 2:

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


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

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

解决方案 3:

伊班

注意:此答案仅适用于 IPython 和使用它的项目,例如 Jupyter。

只需使用foo????foo

如果您使用的是 IPython,则需要键入foo????foo才能查看完整的源代码。要仅查看函数中的文档字符串,请使用foo??foo。这在 Jupyter 笔记本中也有效。

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:

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

解决方案 5:

虽然我一般都同意这inspect是一个很好的答案,但我不同意您无法获取解释器中定义的对象的源代码。如果使用dill.source.getsourcefrom dill,您可以获取函数和 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

>>> 

解决方案 6:

扩展一下 runeh 的回答:

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

>>> import inspect

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

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

编辑:正如@0sh 指出的那样,此示例可以使用ipython但不能使用普通的python。但是,当从源文件导入代码时,两者都应该没问题。

解决方案 7:

由于此帖子被标记为此其他帖子的重复,因此我在此回答“lambda”的情况,尽管 OP 与 lambda 无关。

因此,对于未在其自己的行中定义的 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 文档。顺便说一下,我是作者 ;)

解决方案 8:

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

import inspect

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

print(inspect.getsource(get_my_code))

您可以在以下链接上查看更多选项。
检索您的 Python 代码

解决方案 9:

请注意,只有当 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 函数。这里粘贴的代码太多了,所以看看这个函数的实现。

解决方案 10:

总结一下:

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

解决方案 11:

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

例如

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

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

func.source = funcstring

解决方案 12:

Rafał Dowgird 的回答指出:

我相信如果该函数是从字符串、流编译的或者从编译文件导入的,那么您无法检索其源代码。

但是,可以检索从字符串编译的函数的源代码,前提是编译代码还在linecache.cache字典中添加了一个条目:

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 等调试器能够逐步执行代码。

解决方案 13:

如果之前所有优秀的方法都失败了,你仍然陷入困境(!!),你可以尝试使你的函数崩溃并使用traceback

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用