python pdoc
# Python pdoc:一个被低估的文档生成工具
它到底是个啥
Python pdoc 是个自动文档生成器。和市面上那些花里胡哨的工具不同,它走的是极简路线——不需要配置文件,不需要指定模板,甚至连命令行参数都少得可怜。你要做的事就是安装它,然后告诉它你要给哪个模块生成文档。
它的工作方式很简单:导入你的 Python 代码,解析文档字符串(docstring),生成 HTML 页面。这个过程完全基于运行时类型信息,这意味着它能看到变量类型、函数签名、类继承关系这些东西。有些工具是静态分析的,只能看到表面,pdoc 则是真正把代码跑一遍来理解它。
拿养猫打个比方,静态分析就像只看猫的外表,知道它是橘猫、胖、爱睡觉。而 pdoc 的做法更像把猫抱起来摸一摸,发现它怕水、喜欢吃罐头的品牌、抓沙发的具体角度。对,它就是这么个不嫌麻烦的性子。
它能干哪些事
生成基础文档。这是基本功。你写好模块,pdoc 会帮你把模块里的函数、类、方法、属性、异常全都整理成漂亮的页面。文档字符串怎么写,它就怎么展示。支持 Markdown 格式的文档字符串,所以你可以在注释里写标题、列表、代码块这些。
自动链接。如果一个函数返回另一个类的实例,pdoc 会自动给那个类名加上超链接。如果你在文档字符串里提到其他模块的函数,它也能识别出来并链接过去。这个功能省事儿,尤其当你处理大型项目时,少了很多手动维护的痛苦。
支持私有成员。默认情况下,pdoc 不会显示以下划线开头的名字。但你可以通过参数告诉它:把这些隐藏的也展示出来。这在对内部分享代码时很有用,有时候用户并不在意某个函数“应该”是私有的,他们只想看所有能用的东西。
处理包和子模块。如果你的代码是包结构的,比如 my_package/sub_module.py,pdoc 能递归地生成所有子模块的文档,并且自动建立索引页面。你不需要写什么__all__来指定暴露哪些内容,它默认就能处理好。
搜索功能。生成的 HTML 页面自带搜索框。用户可以在文档里搜函数名、类名,甚至文档字符串里的关键词。这个搜索是基于前端的,意味着你不需要架设任何后端服务,直接把文档丢到服务器上就能用。
在没有网络的环境下,pdoc 的这一整套本地可用的功能实际上挺实用的。有些公司内部开发环境是隔离的,不能上传文档到云平台,没法用 Read the Docs,这时候 pdoc 就成了为数不多的选择之一。
怎么用起来
安装很简单。pip 一行搞定:
pipinstallpdoc基本用法是:
pdoc your_module.py这会启动一个本地 Web 服务器,默认绑定在 8080 端口。你在浏览器打开 http://localhost:8080 就能看到文档。如果不想启动服务器,只想生成静态 HTML 文件:
pdoc--html-o./output_dir your_module.py-o指定输出目录,生成的 HTML 文件会放在里面。
如果你处理的是一个包,比如 my_package 目录,可以:
pdoc my_packagepdoc 会自动识别包结构,生成索引页面。
还有一些实用参数:
--no-include-undocumented:不显示没有文档字符串的成员。有时候代码里有大量辅助函数,没写注释,这些就没必要展示给用户看了。--include-abstract:包含抽象方法。用到 ABC 模块的时候,抽象方法默认是隐藏的,但这个参数能让它们现形。--exclude:排除特定模块。如果你的包里有测试模块或者实验性代码,可以用这个参数把它们从文档里剔除。
让我给个具体的例子。假设你有一个处理短信的模块,叫sms_utils.py。它的内容类似这样:
defsend_message(phone_number,content,provider='twilio'):"""发送短信。 Args: phone_number: 收件人手机号,需包含国家代码。 content: 短信内容,不超过 160 个字符。 provider: 短信服务商,默认为 'twilio'。 Returns: 如果发送成功返回 True,否则返回 False。 """# 实现略pass执行pdoc sms_utils.py后,你会在浏览器里看到这个函数,文档字符串里的参数说明、返回值描述都会以整洁的格式呈现。如果函数内部有类型注解(比如def send_message(phone: str) -> bool:),类型信息也会被展示。
几个用起来更顺手的技巧
文档字符串要写得像在和人说话,不是在写说明书。
说白了,pdoc 的展示效果取决于你的文档字符串质量。如果你只写一句 “This function sends a message”,文档出来就是这个样子。如果能按 Google 风格或者 NumPy 风格写清楚参数、返回值、异常,文档会显得专业很多。pyment 这个工具可以帮你自动转换现有的文档字符串风格,虽然我没怎么用过,不过听说挺顺手。
给模块和类加上模块级别的文档字符串。
很多人只在函数上写文档,却忽略了模块本身。pdoc 会把模块顶部的注释(如果有的话)作为模块的说明显示在页面里。同样,类定义上面的文档字符串也会被展示。这些地方别浪费了,写一两句话说明这个模块或类是干什么的,用户直接省了不少理解成本。
不要过度依赖__all__来控制显示。
有些开发者喜欢用__all__来精确控制哪些名字对外可见。pdoc 不强制你用这个,它默认就不显示私有成员。如果你要显示更精细的控制,可以用--include-no-documented配合--exclude,比修改代码本身要灵活。毕竟改__all__可能会影响其他工具的行为,比如用from module import *导入时。
把文档部署到静态服务器上。
生成静态 HTML 后,可以直接丢到 nginx、Apache 或者 S3 上。不需要 Python 运行时,页面是纯前端的。也不需要有动态语言支持,只需要 Web 服务器能提供静态资源就行。这样文档的访问和加载都会很快,而且没有依赖问题。
和 CI/CD 集成起来。
可以在代码仓库的 CI 流程里加一步:在每次发布新版本时,自动运行 pdoc 生成文档,然后上传到某个固定位置。这样文档总是最新的,不需要开发人员手动维护一个独立的文档项目。Sphinx 虽然也能这么做,但 pdoc 的配置更轻量,跑起来不出错的可能性更高——尤其在 Windows 环境下,Sphinx 那种依赖 Makefile 的方式有时会让人头疼。
和其他工具比一比
和 Sphinx 比
Sphinx 是 Python 文档生成领域的老牌工具,功能极其强大。它支持 RST 和 Markdown,可以生成 PDF、EPUB、HTML 等多种格式,能嵌套.. autoclass::指令从代码里提取文档,支持复杂的交叉引用和域机制,拥有庞大的扩展生态系统(比如 Read the Docs 搭配 Sphinx 几乎成了 Python 项目的标准配置)。
但 Sphinx 太重了。要对它认真使用起来,你得写conf.py配置文件,了解 RST 语法的那一堆指令,还要记着运行make html。如果项目小,比如只是一个 2000 行的通用工具库,用 Sphinx 就是杀鸡用牛刀。pdoc 开箱即用,适合这种场景。
和 MkDocs 比
MkDocs 本身不是从代码生成文档的,它是让你手动写 Markdown 文件。但配合 mkdocstrings 插件后,也可以提取 Python 代码的文档字符串。这个组合的可定制性很高,能完全控制文档的结构、theme、导航。如果你的文档需要很强的叙事性(比如入门教程、最佳实践、API 参考三部分),用 MkDocs 就很合适。
pdoc 在这方面就弱了,它生成的页面更接近“技术参考手册”而不是“教程”。它没提供自定义页面的能力,你怎么写 API 它就怎么展示。对于需要讲故事的文档,MkDocs 或者 Sphinx 可能更合适。
和 Doxygen 比
Doxygen 原本是 C++ 的工具,但也支持 Python。它能生成类图、调用图、依赖图这些可视化内容。pdoc 在这方面基本空白。不过说实话,Python 的动态特性决定了静态分析的类图往往不够准确。因为运行时可能动态添加属性或方法,静态分析出来的图表不能反映实际使用情况。所以 Doxygen 的图在 Python 领域的价值有限,pdoc 干脆就没做这方面的功能,也算是一种务实的态度。
和 Javadoc / JSDoc / godoc 这类语言自带的文档工具比
pdoc 和它们的定位基本一样:一个语言的文档生成工具,开箱即用,不需要额外配置。在这一点上,pdoc 做得不错。但它的生态比 JavaScript 社区的 JSDoc 或者 Go 的 godoc 要弱一些——后者有更多的主题模板、更大的用户群、更丰富的插件。不过对于 Python 社区来说,pdoc 的好处是它完全基于 Python 的运行时类型系统,不需要额外写类型注解之外的东西。
有一说一,选择 pdoc 的根本原因不是它比其他的好,而是它不打扰你写代码。你不需要在代码里加:param:指令,不需要写额外的配置文件,不需要记一堆 Python 文档工具特有的语法。你只需要继续用你习惯的方式写文档字符串,pdoc 就能帮你把它们变成干净的 HTML 页面。这种“少即是多”的设计理念,在开源工具里其实并不常见。
