从 .py 文件中提取 Python 函数名称、主体和文档类型
Extracting Python function names, bodies, and doctypes from a .py file
我已经使用 Python 编程多年,但是,我刚刚了解到您可以使用如下命令:
<function>.__doc__
到return Python 函数的文档字符串!但是,这仍然不足以完成我想要完成的任务。我需要能够提取特定 .py 文件中定义的每个函数的名称,并提取函数名称文档字符串和主体。例如,假设我有以下 .py 文件:
import numpy as np
def get_palindrome(string):
"""Returns the palindrome of the string argument"""
return string[::-1]
def break_my_computer():
"""Destroys your RAM"""
a = []
while True:
a.append(1)
这样应该可以return以下信息:
info = {1: {
'name': 'get_palindrome',
'docstring': 'Returns the palindrome of the string argument',
'body': 'return string[::-1]'
},
2: {
'name': 'break_my_computer',
'docstring': 'Destroys your RAM',
'body': 'a = []\nwhile True:\n a.append(1)'
} }
在Python中获取此信息的最简单方法是什么(我最好不想使用正则表达式库或进行任何文本解析和匹配)。
注意:当遇到多行文档字符串或函数体时,\n(换行)命令应该出现在相应的输出中;制表符应由命令或空格表示。
正确答案是 - 不要这样做!
无论如何我都会去做。
你的问题的前两部分很简单,所以我先把它弄清楚:
import inspect
import module_name as module
# This bit is for if you want to load the module from a file by path, mutually exclusive with previous line
# import importlib
#
# spec = importlib.util.spec_from_file_location("module_name", "/path/to/module_name.py")
# module = importlib.util.module_from_spec(spec)
# spec.loader.exec_module(module)
funcs = []
for name, value in vars(module).items():
if name.startswith("_") or not callable(value):
continue
doc = inspect.getdoc(value)
code = marshal.dumps(value.__code__)
funcs.append({"name": name, "docstring": doc, "body": code})
现在我们到了难点 - body
。无法直接阅读源代码,因为 Python 根本不存储它。您当然可以使用 getsource 读取文件,但这不适用于自 python 加载后在磁盘上修改的模块。如果您想采用这种方法,请遵循以下代码:
import inspect
import module_name as module
# This bit is for if you want to load the module from a file by path, mutually exclusive with previous line
# import importlib
#
# spec = importlib.util.spec_from_file_location("module_name", "/path/to/module_name.py")
# module = importlib.util.module_from_spec(spec)
# spec.loader.exec_module(module)
funcs = []
for name, value in vars(module).items():
if name.startswith("_") or not callable(value):
continue
doc = inspect.getdoc(value)
code = inspect.getsource(value).split(":", maxsplit=1)[1]
funcs.append({"name": name, "docstring": doc, "body": code})
print(funcs)
解决这个问题最好的办法就是根本不存储源代码。您应该改为使用 marshal
模块来序列化代码。这 将 在 python 的主要版本之间中断,并且有点丑陋。如果有任何方法可以避免存储函数代码,请这样做,因为它存在安全风险。
包括编组的完整代码:
import inspect
import marshal
import types
import module_name as module
# This bit is for if you want to load the module from a file by path, mutually exclusive with previous line
# import importlib
#
# spec = importlib.util.spec_from_file_location("module_name", "/path/to/module_name.py")
# module = importlib.util.module_from_spec(spec)
# spec.loader.exec_module(module)
funcs = []
for name, value in vars(module).items():
if name.startswith("_") or not callable(value):
continue
doc = inspect.getdoc(value)
code = marshal.dumps(value.__code__)
funcs.append({"name": name, "docstring": doc, "body": code})
for value in funcs:
name = value["name"]
doc = value["docstring"]
code = value["body"]
# invoke all the functions
func = types.FunctionType(marshal.loads(code), globals(), name)
func.__doc__ = doc
func()
我已经使用 Python 编程多年,但是,我刚刚了解到您可以使用如下命令:
<function>.__doc__
到return Python 函数的文档字符串!但是,这仍然不足以完成我想要完成的任务。我需要能够提取特定 .py 文件中定义的每个函数的名称,并提取函数名称文档字符串和主体。例如,假设我有以下 .py 文件:
import numpy as np
def get_palindrome(string):
"""Returns the palindrome of the string argument"""
return string[::-1]
def break_my_computer():
"""Destroys your RAM"""
a = []
while True:
a.append(1)
这样应该可以return以下信息:
info = {1: {
'name': 'get_palindrome',
'docstring': 'Returns the palindrome of the string argument',
'body': 'return string[::-1]'
},
2: {
'name': 'break_my_computer',
'docstring': 'Destroys your RAM',
'body': 'a = []\nwhile True:\n a.append(1)'
} }
在Python中获取此信息的最简单方法是什么(我最好不想使用正则表达式库或进行任何文本解析和匹配)。
注意:当遇到多行文档字符串或函数体时,\n(换行)命令应该出现在相应的输出中;制表符应由命令或空格表示。
正确答案是 - 不要这样做!
无论如何我都会去做。
你的问题的前两部分很简单,所以我先把它弄清楚:
import inspect
import module_name as module
# This bit is for if you want to load the module from a file by path, mutually exclusive with previous line
# import importlib
#
# spec = importlib.util.spec_from_file_location("module_name", "/path/to/module_name.py")
# module = importlib.util.module_from_spec(spec)
# spec.loader.exec_module(module)
funcs = []
for name, value in vars(module).items():
if name.startswith("_") or not callable(value):
continue
doc = inspect.getdoc(value)
code = marshal.dumps(value.__code__)
funcs.append({"name": name, "docstring": doc, "body": code})
现在我们到了难点 - body
。无法直接阅读源代码,因为 Python 根本不存储它。您当然可以使用 getsource 读取文件,但这不适用于自 python 加载后在磁盘上修改的模块。如果您想采用这种方法,请遵循以下代码:
import inspect
import module_name as module
# This bit is for if you want to load the module from a file by path, mutually exclusive with previous line
# import importlib
#
# spec = importlib.util.spec_from_file_location("module_name", "/path/to/module_name.py")
# module = importlib.util.module_from_spec(spec)
# spec.loader.exec_module(module)
funcs = []
for name, value in vars(module).items():
if name.startswith("_") or not callable(value):
continue
doc = inspect.getdoc(value)
code = inspect.getsource(value).split(":", maxsplit=1)[1]
funcs.append({"name": name, "docstring": doc, "body": code})
print(funcs)
解决这个问题最好的办法就是根本不存储源代码。您应该改为使用 marshal
模块来序列化代码。这 将 在 python 的主要版本之间中断,并且有点丑陋。如果有任何方法可以避免存储函数代码,请这样做,因为它存在安全风险。
包括编组的完整代码:
import inspect
import marshal
import types
import module_name as module
# This bit is for if you want to load the module from a file by path, mutually exclusive with previous line
# import importlib
#
# spec = importlib.util.spec_from_file_location("module_name", "/path/to/module_name.py")
# module = importlib.util.module_from_spec(spec)
# spec.loader.exec_module(module)
funcs = []
for name, value in vars(module).items():
if name.startswith("_") or not callable(value):
continue
doc = inspect.getdoc(value)
code = marshal.dumps(value.__code__)
funcs.append({"name": name, "docstring": doc, "body": code})
for value in funcs:
name = value["name"]
doc = value["docstring"]
code = value["body"]
# invoke all the functions
func = types.FunctionType(marshal.loads(code), globals(), name)
func.__doc__ = doc
func()