PEP 287 – reStructuredText Docstring 格式
- 作者:
- David Goodger <goodger at python.org>
- 讨论至:
- Doc-SIG 邮件列表
- 状态:
- 活跃
- 类型:
- 信息性
- 创建日期:
- 2002年3月25日
- 发布历史:
- 2002年4月2日
- 取代:
- 216
摘要
当纯文本不足以表达内联文档时,Python 程序员一直在寻找一种用于 docstring 的格式。本 PEP 提议采用 reStructuredText 标记作为 Python docstring 以及 PEP 和辅助文档中结构化纯文本文档的标准标记格式。reStructuredText 是一种丰富、可扩展且易于阅读的所见即所得的纯文本标记语法。
本文只讨论 docstring 的低级语法。本 PEP 完全不关心 docstring 的语义或处理(请参阅 PEP 256 以了解“Docstring PEPs 的路线图”)。它也不是试图废弃纯文本 docstring,纯文本 docstring 始终是合法的。reStructuredText 标记是那些想要更具表达力的 docstring 的人的替代方案。
好处
程序员天生就是懒惰的。我们通过函数、类、模块和子系统重用代码。通过其 docstring 语法,Python 允许我们从内部文档化我们的代码。Python 文档特别兴趣小组 (Doc-SIG) 的“圣杯”是一种标记语法和工具集,可以实现自动文档,其中 Python 系统的 docstring 可以根据上下文提取并处理成有用的、高质量的文档,用于多种目的。
文档标记语言有三类客户:编写文档的作者、处理数据的软件系统以及最终消费者(最重要的群体)——读者。大多数标记都是为作者和软件系统设计的;读者只能看到处理后的形式,无论是在纸上还是通过浏览器软件。reStructuredText 则不同:它旨在以源代码形式易于阅读,无需预先了解标记。reStructuredText 以纯文本格式完全可读,并且许多标记形式与常见用法匹配(例如,*强调*),因此阅读起来非常自然。然而,它足够丰富以生成复杂的文档,并且可扩展,因此限制很少。当然,要编写 reStructuredText 文档需要一些预先知识。
该标记提供了功能性和表达性,同时在源文本中保持了易读性。处理后的形式(HTML 等)使读者可以访问所有内容:内联实时超链接;与脚注之间的实时链接;自动目录(带实时链接!);表格;用于图表等的图像;令人愉悦、易读的样式文本。
reStructuredText 解析器现已可用,是 Docutils 项目的一部分。独立的 reStructuredText 文档和 PEP 可以转换为 HTML;其他输出格式的写入器正在开发中,并将随着时间的推移而可用。一个 Python 源“阅读器”的工作正在进行中,它将实现从 docstring 的自动文档。鼓励现有自动文档工具的作者将 reStructuredText 解析器集成到他们的项目中,或者更好的是,联手为 Python 标准库生产一套世界级的工具。
工具将在不久的将来可用,它们将允许程序员从现有的 docstring 中“免费”生成用于在线帮助的 HTML、用于多种用途的 XML,以及最终用于打印文档的 PDF、DocBook 和 LaTeX。采用标准至少将通过防止进一步“重复发明轮子”来惠及 docstring 处理工具。
最终,PyDoc(现有的唯一标准自动文档工具)可以添加 reStructuredText 支持。在此期间,它对 reStructuredText 标记不会有任何问题,因为它将所有 docstring 视为预格式化的纯文本。
目标
这些是 Doc-SIG 中讨论的 docstring 格式的普遍接受的目标
- 它必须以源代码形式对普通观察者可读。
- 它必须易于使用任何标准文本编辑器输入。
- 它不需要包含可以从解析模块中推导出的信息。
- 它必须包含足够的信息(结构),以便可以转换为任何合理的标记格式。
- 必须能够在 docstring 中编写模块的整个文档,而不会感到受标记语言的限制。
reStructuredText 达到了并超越了所有这些目标,并设定了自己更严格的目标。请参阅下面的 Docstring-重要功能。
本 PEP 的目标如下
- 将 reStructuredText 确立为 docstring(Python 模块和包的内联文档)、PEPs、README 类型文件和其他独立文档的标准结构化纯文本格式。将通过 Python 社区共识和最终的 BDFL 声明寻求“接受”状态。
请注意,reStructuredText 被提议为 一个 标准,而不是 唯一的 标准。它的使用将完全是可选的。那些不想使用它的人不必使用。
- 征求并解决 Python 社区提出的任何相关问题。
- 鼓励社区支持。只要存在多个相互竞争的标记,开发社区就会分裂。一旦标准存在,人们就会开始使用它,并且势头将不可避免地聚集起来。
- 整合来自相关自动文档项目的努力。希望感兴趣的开发人员能够联手开发一个联合/合并/通用实现。
一旦 reStructuredText 成为 Python 标准,就可以将精力集中在工具上,而不是争论标准。Python 需要一套标准的文档工具。
关于 PEPs,可以采用以下一种或两种策略
- 保持现有 PEP 部分结构构造(单行部分标题,缩进正文)。子部分可以被禁止,或者通过缩进正文中的 reStructuredText 样式下划线标题来支持。
- 用 reStructuredText 语法替换 PEP 部分结构构造。部分标题将需要下划线,子部分将开箱即用,并且正文无需缩进(除了块引用)。
推荐策略 (b),并且其实现已完成。
对 RFC 2822 标题的支持已添加到 PEP 的 reStructuredText 解析器中(在特定上下文:文档的第一个连续块中是明确的)。可能需要具体指定 PEP 部分标题允许哪些上/下划线样式,以保持一致性。
基本原理
docstring 缺乏标准语法阻碍了用于将 docstring 提取和转换为标准格式(例如 HTML、DocBook、TeX)文档的标准工具的开发。已经有许多提议的标记格式和变体,以及许多与这些提议相关的工具,但如果没有标准的 docstring 格式,它们未能获得强大的追随者,和/或半途而废。
在 Doc-SIG 存在的整个过程中,从未就单一标准 docstring 格式达成共识。出于以下原因(以及其他原因),人们一直在寻求一种轻量级、隐式的标记
- 在 Python 代码中编写的 docstring 可以从交互式解释器中获取,并且可以“打印”。因此,使用纯文本易于阅读。
- 程序员希望为他们的 docstring 添加结构,而又不牺牲原始 docstring 的可读性。未修饰的纯文本无法转换为(“升级”)有用的结构化格式。
- 显式标记(如 XML 或 TeX)被普遍认为是外行人难以阅读的。
- 隐式标记在美学上与简洁的 Python 语法兼容。
多年来,在 Doc-SIG 上提出了许多用于 docstring 的替代标记;下面列出了一个有代表性的样本。每个样本都根据上述目标进行了简要分析。请注意,这 并非 旨在成为所有现有标记系统的独占列表;还有许多其他标记(Texinfo、Doxygen、TIM、YODL、AFT 等)未提及。
- XML、SGML、DocBook、HTML、XHTML
XML 和 SGML 是显式、格式良好的元语言,适用于各种文档。XML 是 SGML 的一个变体。它们最好用于幕后,因为对于未经训练的眼睛来说,它们冗长、难以输入,并且作为源代码阅读时过于混乱。DocBook、HTML 和 XHTML 都是 SGML 和/或 XML 的应用程序,并且都共享相同的基本语法和相同的缺点。
- TeX
TeX 与 XML/SGML 类似,因为它也是显式的,但它不太容易编写,对于未经训练的人来说也不容易阅读。
- Perl POD
大多数 Perl 模块都以一种称为 POD(Plain Old Documentation)的格式进行文档化。这是一种易于输入、非常低级的格式,与 Perl 解析器紧密集成。有许多工具可以将 POD 文档转换为其他格式:信息、HTML 和 man 页面等等。然而,POD 语法在可读性方面继承了 Perl 本身。
- JavaDoc
Java 类和函数前的特殊注释用于文档化代码。一个用于提取这些注释并将其转换为 HTML 文档的程序称为 javadoc,它是标准 Java 发行版的一部分。然而,JavaDoc 与 HTML 关系非常密切,使用 HTML 标签进行大部分标记。因此,它也存在 HTML 的可读性问题。
- Setext, StructuredText
早期,Setext(结构增强文本)的变体,包括 Zope 公司 的 StructuredText,被提议用于 Python docstring 格式化。此后,这些变体将统称为“STexts”。STexts 的优点是无需特殊知识即可轻松阅读,并且相对容易编写。
尽管一些人(包括大多数现有 Python 自动文档工具)在使用,但到目前为止 STexts 未能成为标准,因为
- STexts 不完整。缺乏人们希望在其 docstring 中使用的“基本”结构,使得 STexts 不尽理想。请注意,这些“基本”结构并非普遍存在;每个人都有自己的要求。
- STexts 有时令人惊讶。文本的某些部分被意外地解释为被标记,导致用户沮丧。
- SText 实现存在 bug。
- 大多数 STexts 都没有正式的规范,除了实现本身。一个有 bug 的实现意味着一个有 bug 的规范,反之亦然。
- 当标记字符用于非标记上下文时,没有办法绕过 SText 标记规则。换句话说,没有办法转义标记。
隐式 STexts 的支持者强烈反对显式标记(XML、HTML、TeX、POD 等)的提议,自 1996 年或更早以来,辩论时断时续。
reStructuredText 是 SText 思想的完整修订和重新诠释,解决了上面列出的所有问题。
规范
reStructuredText 的规范和用户文档非常广泛。此处不重复或总结所有内容,而是提供原始链接。
请先阅读 reStructuredText 入门,这是一个简短而温和的介绍。快速 reStructuredText 用户参考快速总结了所有标记结构。有关完整和详细的信息,请参阅以下文档
此外,StructuredText 的问题 解释了许多关于 StructuredText 的标记决策,而 reStructuredText 语法替代方案记录 记录了独立做出的标记决策。
Docstring-重要功能
- 一种标记转义机制。
反斜杠(
\)用于在非标记目的需要时转义标记字符。然而,内联标记识别规则的构建旨在最大程度地减少对反斜杠转义的需求。例如,尽管星号用于 强调,但在“*”或“(*)”或“x * y”等非标记上下文中,星号不会被解释为标记并保持不变。对于许多非标记用途的反斜杠(例如,描述正则表达式),内联字面量或字面量块是适用的;请参阅下一项。 - 用于包含 Python 源代码和 Python 交互会话的标记:内联字面量、字面量块和 doctest 块。
内联字面量使用
双反引号来指示程序 I/O 或代码片段。在内联字面量中不进行任何标记解释(包括反斜杠转义 [\] 解释)。字面量块(块级字面量文本,例如代码摘录或 ASCII 图形)是缩进的,并在前一个段落末尾用双冒号(“::”)指示(就在这里——>)
if literal_block: text = 'is left as-is' spaces_and_linebreaks = 'are preserved' markup_processing = None
Doctest 块以“>>>”开头,以空行结束。不需要缩进或字面量块双冒号。例如
Here's a doctest block: >>> print 'Python-specific usage examples; begun with ">>>"' Python-specific usage examples; begun with ">>>" >>> print '(cut and pasted from interactive sessions)' (cut and pasted from interactive sessions)
- 隔离 Python 标识符的标记:解释文本。
用单反引号括起来的文本被识别为“解释文本”,其解释取决于应用程序。在 Python docstring 的上下文中,解释文本的默认解释是 Python 标识符。文本将用一个超链接标记,该超链接连接到给定标识符的文档。查找规则与 Python 本身相同:LGB 命名空间查找(本地、全局、内置)。解释文本的“角色”(识别类、模块、函数等)从命名空间查找中隐式确定。例如
class Keeper(Storer): """ Keep data fresher longer. Extend `Storer`. Class attribute `instances` keeps track of the number of `Keeper` objects instantiated. """ instances = 0 """How many `Keeper` objects are there?""" def __init__(self): """ Extend `Storer.__init__()` to keep track of instances. Keep count in `self.instances` and data in `self.data`. """ Storer.__init__(self) self.instances += 1 self.data = [] """Store data in a list, most recent last.""" def storedata(self, data): """ Extend `Storer.storedata()`; append new `data` to a list (in `self.data`). """ self.data = data
每段解释文本都根据包含其 docstring 的块的局部命名空间进行查找。
- 隔离 Python 标识符并指定其类型的标记:带有角色的解释文本。
尽管 Python 源代码上下文阅读器设计为不需要显式角色,但它们仍然可以使用。要明确分类标识符,角色可以以前缀或后缀形式与标识符一起给出。
Use :method:`Keeper.storedata` to store the object's data in `Keeper.data`:instance_attribute:.
为角色选择的语法很冗长,但这是必要的(如果有人有更好的替代方案,请将其发布到 Doc-SIG)。该标记的目的是应该很少需要使用显式角色;它们的使用应保持在绝对最小值。
- 用于“标签列表”或“字段列表”的标记:字段列表。
字段列表表示从字段名称到字段主体的映射。这些主要用于扩展语法,例如“书目字段列表”(表示文档元数据,如作者、日期和版本)和指令的扩展属性(见下文)。它们可用于实现方法论(docstring 语义),例如识别参数、引发的异常等;此类用法超出了本 PEP 的范围。
使用修改后的 RFC 2822 语法,在字段名称 之前 和 之后 都有冒号。字段主体也更加通用;它们可以包含多个字段主体(甚至嵌套的字段列表)。例如
:Date: 2002-03-22 :Version: 1 :Authors: - Me - Myself - I
标准 RFC 2822 标头语法不能用于此构造,因为它具有歧义性。在一行的开头跟着冒号的单词在书面文本中很常见。
- 标记可扩展性:指令和替换。
指令用作 reStructuredText 的扩展机制,一种在不添加新语法的情况下支持新块级构造的方法。已经实现了用于图像、警告(注释、警告等)和目录生成(等等)的指令。例如,以下是如何放置图像
.. image:: mylogo.png
替换定义允许块级指令的功能和灵活性由内联文本共享。例如
The |biohazard| symbol must be used on containers used to dispose of medical waste. .. |biohazard| image:: biohazard.png
- 节结构标记。
reStructuredText 中的节标题通过下划线(和可能上划线)修饰,而不是缩进。例如
This is a Section Title ======================= This is a Subsection Title -------------------------- This paragraph is in the subsection. This is Another Section Title ============================= This paragraph is in the second section.
问答
- reStructuredText 足够丰富吗?
是的,对于大多数人来说是。如果它缺少特定应用程序所需的某些构造,可以通过指令机制添加。如果忽略了有用且常见的构造,并且找到了合适的可读语法,则可以将其添加到规范和解析器中。
- reStructuredText 是不是 太 丰富了?
对于特定的应用程序或个人来说,也许是。总的来说,不是。
从一开始,每当在 Doc-SIG 上提出 docstring 标记语法时,总会有人抱怨缺乏对某种构造的支持。回复通常是,“我们谈论的是 docstring,docstring 不应该有复杂的标记。”问题在于,对一个人来说似乎多余的构造,对另一个人来说可能绝对是必不可少的。
reStructuredText 采取了相反的方法:它提供了一组丰富的隐式标记构造(加上一个用于显式标记的通用扩展机制),允许各种文档。如果这组构造对于特定应用程序来说过于丰富,那么未使用的构造可以通过应用程序特定的覆盖从解析器中删除,或者只是通过约定省略。
- 为什么不使用缩进表示节结构,就像 StructuredText 那样?它不是更“Pythonic”吗?
Guido van Rossum 在 2001 年 6 月 13 日的 Doc-SIG 帖子中写道
我仍然认为使用缩进来表示分节是错误的。如果你看看真实的书籍和其他印刷出版物是如何排版的,你会发现缩进经常被使用,但主要是在节内部级别。缩进可以用来偏移列表、表格、引文、示例等等。(认为 docstring 是不同的,因为它们是文本格式化程序的输入,这种论点是错误的:重点是它们也可以在不经过处理的情况下阅读。)我反对使用缩进是 Pythonic 的论点:文本不是代码,存在不同的传统和惯例。人们为了可读性而展示文本已经超过 30 个世纪了。我们不要不必要地创新。
有关进一步阐述,请参阅 StructuredText 的问题 中 通过缩进进行节结构。
- 为什么将 reStructuredText 用于 PEPs?现有的标准有什么问题?
现有的 PEP 标准在一般表达方面非常有限,对于这种引用丰富的文档类型来说,引用尤其缺乏。PEPs 目前被转换为 HTML,但结果(大多是等宽文本)缺乏吸引力,并且 HTML 的大部分增值潜力(尤其是内联超链接)尚未被开发。
将 reStructuredText 作为 PEP 的标准标记将实现更丰富的表达,包括支持节结构、内联标记、图形和表格。在几个 PEP 中有 ASCII 图形图表,这是纯文本文档所能支持的全部。由于 PEP 以 HTML 形式提供,因此包含适当图表的能力将立即派上用场。
当前的 PEP 实践允许在文本中使用“[1]”形式的引用标记,并且脚注/参考文献本身列在文档末尾的某个部分。目前,引用标记和脚注/参考文献之间没有超链接(这可以通过添加到 pep2html.py 中来实现,但目前的“标记”是模糊的,错误将不可避免)。包含许多引用(例如这个 ;-) 的 PEP 需要大量的来回翻阅。在修订 PEP 时,通常会添加新引用或删除未使用的引用。重新编号引用很痛苦,因为它必须在两个地方完成,并且可能产生连锁效应(插入一个新引用 1,所有其他引用都必须重新编号;始终将新引用添加到末尾是次优的)。引用很容易不同步。
PEPs 将引用用于两个目的:简单的 URL 引用和脚注。reStructuredText 区分两者。PEP 可能包含如下引用
Abstract This PEP proposes adding frungible doodads [1] to the core. It extends PEP 9876 [2] via the BCA [3] mechanism. ... References and Footnotes [1] http://www.example.org/ [2] PEP 9876, Let's Hope We Never Get Here http://peps.python.org/pep-9876/ [3] "Bogus Complexity Addition"
引用 1 是一个简单的 URL 引用。引用 2 是包含文本和 URL 的脚注。引用 3 是仅包含文本的脚注。用 reStructuredText 重写后,这个 PEP 可能看起来像这样
Abstract ======== This PEP proposes adding `frungible doodads`_ to the core. It extends PEP 9876 [#pep9876]_ via the BCA [#]_ mechanism. ... References & Footnotes ====================== .. _frungible doodads: http://www.example.org/ .. [#pep9876] PEP 9876, Let's Hope We Never Get Here .. [#] "Bogus Complexity Addition"
如果需要,URL 和脚注可以定义在其引用附近,使其在源文本中更易阅读,并使 PEP 更易于修订。“参考文献和脚注”部分可以通过文档树转换自动生成。整个 PEP 中的脚注将收集并显示在标准标题下。如果 URL 引用也应明确写出(以引文形式),则可以使用另一个树转换。
URL 引用可以命名(“可分解的小玩意”),并且可以在文档中的多个位置引用,而无需额外的定义。当转换为 HTML 时,引用将替换为内联超链接(HTML <a> 标签)。这两个脚注会自动编号,因此它们将始终保持同步。第一个脚注还包含一个内部引用名称“pep9876”,因此在源文本中更容易看到引用和脚注之间的连接。命名脚注可以多次引用,保持编号一致。
“#pep9876”脚注也可以用引文的形式写成
It extends PEP 9876 [PEP9876]_ ... .. [PEP9876] PEP 9876, Let's Hope We Never Get Here
脚注是带编号的,而引文则使用文本作为其引用。
- 将 docstring 和 PEP 提案分开会更好吗?
如果认为不需要 PEP 标记,则可以删除 PEP 标记提案,或者将其作为单独的 PEP。如果获得接受,PEP 1,《PEP 目的和指南》,以及 PEP 9,《纯文本 PEP 模板示例》将进行更新。
在 Python 中,为所有结构化纯文本用途采用单一一致的标记标准,并将其集中在一处提出,这似乎很自然。
- 现有的 pep2html.py 脚本将现有的 PEP 格式转换为 HTML。新格式的 PEPs 将如何转换为 HTML?
一个集成了 reStructuredText 解析功能的新版 pep2html.py 已完成。Docutils 项目通过“PEP 阅读器”组件支持 PEPs,包括 pep2html.py 中当前的所有功能(PEP 和 RFC 引用的自动识别、电子邮件遮蔽等)。
- 谁来将现有的 PEPs 转换为 reStructuredText?
PEP 作者或志愿者可以根据需要转换现有的 PEP,但没有这样的要求。基于 reStructuredText 的 PEP 将与旧的 PEP 标准共存。答案 6 中提到的 pep2html.py 同时处理新旧标准。
- 为什么将 reStructuredText 用于 README 和其他辅助文件?
答案 4 中给出的关于 PEP 的理由也适用于 README 和其他辅助文件。通过采用标准标记,这些文件可以转换为美观的交叉引用 HTML,并发布到 python.org 上。其他项目的开发人员也可以利用此功能进行自己的文档。
- 与现有标记惯例表面上的相似性会不会造成问题,导致人们编写无效标记(并且没有注意到,因为纯文本看起来很自然)?reStructuredText 对“不太正确”的标记的宽容度如何?
会出现一些失误,就像从一种编程语言转向另一种编程语言一样。与任何语言一样,熟练程度随着经验的增长而提高。幸运的是,reStructuredText 确实是一种非常小的语言。
与任何语法一样,也存在语法错误的可能。期望用户对其输入运行处理系统并检查输出的正确性。
严格来说,reStructuredText 解析器非常严格(它也应该如此;“面对歧义,拒绝猜测的诱惑” 既适用于解析标记也适用于计算机语言)。以下是 reStructuredText 简介 中的设计目标 3
明确。标记规则不得开放解释。对于任何给定的输入,应该只有一个可能的输出(包括错误输出)。虽然不宽容,但解析器同时也会通过生成有用的诊断输出(“系统消息”)来提供帮助。解析器会报告问题,并指示其严重程度(从低到高:调试、信息、警告、错误、严重)。用户或客户端软件可以决定报告阈值;他们可以忽略低级别问题,或者导致高级别问题立即停止处理。问题在解析期间报告并包含在输出中,通常在问题源和解释问题的系统消息之间有双向链接。
- Python 标准库模块中的 docstring 会转换为 reStructuredText 吗?
不会。Python 的库参考文档是与源代码分开维护的。Python 标准库中的 docstring 不应试图复制库参考文档。Python 标准库中 docstring 的当前策略是,它们应该仅仅是简洁的提示,简单且不带标记(尽管许多 确实 包含临时隐式标记)。
- 我想用 Unicode 编写所有字符串。会有什么问题吗?
解析器完全支持 Unicode。Docutils 支持任意输入和输出编码。
- 社区为什么需要一个新的结构化文本设计?
现有的结构化文本设计存在缺陷,原因如上文“理由”所述。reStructuredText 的目标是在“可读纯文本”媒介的限制内,成为一个完整的标记语法。
- 现有文档方法有什么问题?
现有的方法是什么?对于 Python docstring,目前 没有 官方标准标记格式,更不用说类似于 JavaDoc 的文档方法了。方法论的问题比语法(本 PEP 旨在解决)的层次要高得多。它可能更具争议性且更难解决,因此有意排除在本次讨论之外。
版权
本文档已置于公共领域。
致谢
部分文本借用了 Moshe Zadka 编写的 PEP 216,《Docstring 格式》。
特别感谢 Python Doc-SIG 的所有过去和现在的成员。
来源:https://github.com/python/peps/blob/main/peps/pep-0287.rst