How can I get the source code of a Python function?
假设我有一个python函数,定义如下:
1 2 3 4 | def foo(arg1,arg2): #do something with args a = arg1 + arg2 return a |
我可以使用
如果函数来自文件系统上可用的源文件,那么
如果
1 2 3 4 | def foo(arg1,arg2): #do something with args a = arg1 + arg2 return a |
然后:
1 2 3 | import inspect lines = inspect.getsource(foo) print(lines) |
返回:
1 2 3 4 | def foo(arg1,arg2): #do something with args a = arg1 + arg2 return a |
但我相信,如果函数是从字符串、流或从编译文件导入的,那么您就无法检索其源代码。
inspect模块具有从python对象检索源代码的方法。不过,似乎只有当源位于文件中时,它才起作用。如果你有,我想你不需要从对象中获取源代码。
如果源代码不可用,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | >>> 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 |
如果您使用的是ipython,那么您需要键入"foo"?"
1 2 3 4 5 6 7 8 9 10 | 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 |
虽然我一般认为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | >>> 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 >>> |
扩展runeh的答案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | >>> 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所指出的,这个例子使用
您可以使用
1 2 3 4 5 6 7 | import inspect def get_my_code(): x ="abcd" return x print(inspect.getsource(get_my_code)) |
您可以在下面的链接中查看更多选项。检索您的python代码
总结:
1 2 | import inspect print("".join(inspect.getsourcelines(foo)[0])) |
如果您自己严格定义函数,而且定义相对较短,那么没有依赖关系的解决方案将是在字符串中定义函数,并将表达式的eval()赋给您的函数。
例如。
1 2 | funcstring = 'lambda x: x> 5' func = eval(funcstring) |
然后可以选择将原始代码附加到函数:
1 | func.source = funcstring |
请注意,只有当lambda在单独的行上给出时,接受的答案才有效。如果您将它作为一个参数传递给一个函数,并且希望将lambda的代码作为对象来检索,那么这个问题会变得有点棘手,因为
例如,考虑一个文件
1 2 3 4 5 6 7 8 | import inspect def main(): x, f = 3, lambda a: a + 1 print(inspect.getsource(f)) if __name__ =="__main__": main() |
执行它会给你(注意缩进!):
1 | x, f = 3, lambda a: a + 1 |
为了检索lambda的源代码,我认为最好的办法是重新解析整个源文件(使用
我们必须在契约库IContract的设计中做到这一点,因为我们必须解析lambda函数,并将其作为参数传递给修饰符。这里要粘贴的代码太多,请看一下这个函数的实现。
因为这篇文章被标记为另一篇文章的副本,所以我在这里回答"lambda"这个问题,尽管OP不是关于lambdas的。
因此,对于没有在自己的行中定义的lambda函数:除了marko.ristin的答案之外,您可能希望使用mini lambda或使用此答案中建议的sympy。
mini-lambda 更轻,支持任何类型的操作,但只适用于单个变量。SymPy 较重,但更配备数学/微积分运算。特别是它可以简化表达式。它还支持同一表达式中的多个变量。
以下是使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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)) |
它正确地产生
1 2 3 4 5 6 | def foo(arg1, arg2): # do something with args a = arg1 + arg2 return a x ** 2 |
详见
如果使用ipython,另一个选项是在函数名后使用
1 2 3 4 5 6 7 8 9 10 11 12 13 | [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 |
我相信变量名不会存储在pyc/pyd/pyo文件中,因此如果没有源文件,就无法检索准确的代码行。