问题场景
小众开发者的仓库,没有做文档,直接上源码,源码太长但好在源码里夹带着注释和文档,
你需要清楚地知道每一个类、每一个属性、方法的输入、输出,以及功能是什么?
有没有省时省力一点提取注释文档的方法?
此处我以某个计算生物学库aiupred_lib为例,比较小众,开发者没怎么给文档+源码有一点点长
一般计算生物学的库, 其实实现的规范没有计算机那么严谨,
一般文档中说import XXX, 其实就是该软件安装路径下有个XXX.py.
以aiupred_lib为例, 就是该仓库软件下载解压文件夹下有一个aiupre_lib.py
要一次性输出 aiupred_lib 库中所有方法(含函数、类、类方法等)及其对应文档,核心是利用 Python 内置的反射机制(如 dir()、getattr())和文档提取工具(如 inspect 模块)。
下面本博客就是分场景的完整实现方案,覆盖库的所有可调用成员,并清晰展示文档信息。
核心原理
dir(aiupred_lib):获取库中所有成员名称(包括函数、类、变量等)。inspect模块:过滤出「可调用对象」(排除普通变量),并提取其详细文档( docstring )、参数列表等信息。- 分类输出:区分「顶层函数」和「类及其方法」,避免信息混乱(库中通常包含类,类内部又有方法)。
参考:https://github.com/MaybeBio/bioinfor_script_modules/blob/main/38_Library_Doc_interface.py
step1:导入必要模块并加载目标库
首先确保 aiupred_lib 已安装且可导入(若需添加路径,可结合 sys.path 逻辑):
参考之前的博客:https://blog.youkuaiyun.com/weixin_62528784/article/details/149749704?spm=1001.2014.3001.5502
假设安装路径为/path/to/aiupred/folder
# 1, 在终端中, 需要
export PYTHONPATH="${PYTHONPATH}:/path/to/aiupred/folder"
如果PYTHONPATH为空, 则直接export PYTHONPATH="/path/to/aiupred/folder"
可以在 ~/.bashrc或者是~/.zshrc中修改
# 2, 在Notebook中
AIUpred_PATH = "/path/to/aiupred/folder"
if AIUpred_PATH not in sys.path:
sys.path.append(AIUpred_PATH)
import aiupred_lib
import sys
import os
import inspect # 核心:用于提取对象信息和文档
# 导入目标库
import aiupred_lib # 确保这行不报错,否则需检查路径或库安装
step2:定义工具函数(提取文档+过滤可调用对象)
封装两个核心工具函数,简化后续逻辑:
def get_object_doc(obj, obj_name: str) -> str:
"""提取对象的文档信息(docstring + 参数列表)"""
# 1. 提取docstring(若没有文档,返回提示)
docstring = inspect.getdoc(obj) or "⚠️ 无官方文档"
# 2. 提取参数列表(针对函数/方法)
try:
# 获取签名(参数名、默认值等)
sig = inspect.signature(obj)
params_info = f"参数列表: {str(sig)}"
except (ValueError, TypeError):
# 非函数/方法(如类本身),无参数列表
params_info = "❌ 非可调用对象,无参数列表"
# 3. 组合文档信息
return f"""
【{obj_name}】
{params_info}
------------------------------
文档说明:
{docstring}
======================================================================"""
def is_callable_member(member) -> bool:
"""过滤:仅保留「可调用对象」(函数、类、类方法等),排除普通变量"""
# 排除内置特殊成员(如 __name__、__doc__)
if inspect.ismodule(member):
return False # 排除子模块(若库包含子模块,可按需调整)
# 保留:函数、类、实例方法、类方法、静态方法
return (inspect.isfunction(member)
or inspect.isclass(member)
or inspect.ismethod(member)
or inspect.ismethoddescriptor(member))
step3:遍历库成员,分类输出所有方法及文档
分「顶层函数/类」和「类的内部方法」两类输出,结构更清晰:
def print_all_methods_with_docs(library) -> None:
"""主函数:输出库中所有可调用成员及其文档"""
print(f"=== 开始输出 {library.__name__} 库的所有方法及文档 ===")
print(f"库路径: {library.__file__}\n")
# 1. 获取库的所有成员名称(过滤掉内置特殊成员,如 __init__)
all_member_names = [name for name in dir(library) if not name.startswith("__")]
# 2. 遍历成员,分类处理
for member_name in all_member_names:
# 获取成员对象(如函数、类)
member = getattr(library, member_name)
# 过滤:仅处理可调用对象
if not is_callable_member(member):
continue
# 场景A:成员是「类」(需进一步输出类的内部方法)
if inspect.isclass(member):
print(f"📦 类: {member_name}")
print(get_object_doc(member, member_name)) # 输出类本身的文档
# 提取类的所有方法(过滤内置特殊方法)
class_methods = [
meth_name for meth_name in dir(member)
if not meth_name.startswith("__")
]
for meth_name in class_methods:
meth = getattr(member, meth_name)
if is_callable_member(meth): # 确保是方法(而非类变量)
print(f" 🔧 方法: {member_name}.{meth_name}")
print(get_object_doc(meth, f"{member_name}.{meth_name}"))
# 场景B:成员是「顶层函数」(直接输出)
else:
print(f"🔧 顶层函数: {member_name}")
print(get_object_doc(member, member_name))
print(f"=== {library.__name__} 库所有方法及文档输出完毕 ===")
# 执行主函数,输出结果
if __name__ == "__main__":
print_all_methods_with_docs(aiupred_lib)
比如说我这里的文档查看:
如果是朴素的方法,
如果只是看用dir方法或者inspect模块:先dir查看,再细节用inspect模块


比如说这里有一个’calculate_energy’,再用inspect模块中的方法查看:

或者直接用help:

未免显得太麻烦了,其实就是效率和效果不好。
如果想要高屋建瓴的概览,直接查看整个库的帮助文档,


写得短一点还好,直接硬啃即可,写得长一点就麻烦了。
所以用上面自定义函数的方法,1个1个地提取,效果如下:

写得有点问题,中间transformer类输出方法冗余有点多,后续矫正一下。
一般直接看顶层函数即可



关键注意事项
- 处理「子模块」:若
aiupred_lib包含子模块(如aiupred_lib.models),上述代码仅输出顶层成员。若需包含子模块,需在is_callable_member中移除inspect.ismodule(member)的判断,并递归遍历子模块(可留言补充需求)。 - 文档完整性:输出的文档依赖库本身是否编写了
docstring(官方库通常会写)。若某方法显示「⚠️ 无官方文档」,可能是库未提供该方法的说明,比如说上面某些方法,一些小众领域的库,开发者就是直接全代码无注释,提取不出来什么。 - 特殊成员过滤:代码中排除了以
__开头的内置成员(如__init__、__str__),若需查看这些特殊方法,可删除if not name.startswith("__")的过滤条件。
拓展:将结果保存到文件
若输出内容过多,可将结果保存到 txt 文件,方便后续查阅:
# 在 print_all_methods_with_docs 函数中,添加文件写入逻辑
def print_all_methods_with_docs(library, save_to_file: bool = True) -> None:
output_content = [] # 用列表存储所有内容,最后统一写入
output_content.append(f"=== {library.__name__} 库方法及文档 ===")
output_content.append(f"库路径: {library.__file__}\n")
# 后续遍历成员时,将原本 print 的内容 append 到 output_content
# 示例:
# output_content.append(f"🔧 顶层函数: {member_name}")
# output_content.append(get_object_doc(member, member_name))
# 最后打印并保存
final_content = "\n".join(output_content)
print(final_content)
if save_to_file:
with open(f"{library.__name__}_docs.txt", "w", encoding="utf-8") as f:
f.write(final_content)
print(f"\n✅ 文档已保存到: {library.__name__}_docs.txt")
105

被折叠的 条评论
为什么被折叠?



