Following system colour scheme - Python 增强提案 Selected dark colour scheme - Python 增强提案 Selected light colour scheme - Python 增强提案

Python 增强提案

PEP 257 – Docstring 约定

作者:
David Goodger <goodger at python.org>, Guido van Rossum <guido at python.org>
讨论至:
Doc-SIG 邮件列表
状态:
活跃
类型:
信息性
创建日期:
2001 年 5 月 29 日
发布历史:
2001 年 6 月 13 日

目录

摘要

本 PEP 记录了与 Python Docstring 相关的语义和约定。

基本原理

本 PEP 的目的是标准化 Docstring 的高级结构:它们应该包含什么,以及如何表达(不涉及 Docstring 内的任何标记语法)。本 PEP 包含的是约定,而不是法律或语法。

“一个通用的约定提供了可维护性、清晰度、一致性,也是良好编程习惯的基础。它不会强迫你违背自己的意愿去遵循它。这就是 Python!”

—Tim Peters 在 comp.lang.python 上,2001-06-16

如果你违反这些约定,最糟糕的情况也只是得到一些不悦的目光。但有些软件(例如 Docutils Docstring 处理系统 PEP 256, PEP 258)会知晓这些约定,因此遵循它们会让你获得最佳结果。

规范

什么是 Docstring?

Docstring 是一个字符串字面量,它作为模块、函数、类或方法定义中的第一个语句出现。这样的 Docstring 会成为该对象的 __doc__ 特殊属性。

所有模块通常都应该有 Docstring,并且模块导出的所有函数和类也应该有 Docstring。公共方法(包括 __init__ 构造函数)也应该有 Docstring。包可以在包目录中 __init__.py 文件的模块 Docstring 中进行文档说明。

Python 代码中其他地方出现的字符串字面量也可以作为文档。它们不被 Python 字节码编译器识别,也不能作为运行时对象属性访问(即不赋值给 __doc__),但有两种额外类型的 Docstring 可以被软件工具提取。

  1. 紧接在模块、类或 __init__ 方法顶层简单赋值之后的字符串字面量被称为“属性 Docstring”。
  2. 紧接在另一个 Docstring 之后的字符串字面量被称为“附加 Docstring”。

请参阅 PEP 258,“Docutils 设计规范”,以获取属性和附加 Docstring 的详细描述。

为保持一致性,Docstring 始终使用 """三重双引号"""。如果 Docstring 中包含任何反斜杠,请使用 r"""原始三重双引号"""

Docstring 有两种形式:单行 Docstring 和多行 Docstring。

单行 Docstring

单行 Docstring 适用于非常明显的情况。它们确实应该只占用一行。例如:

def kos_root():
    """Return the pathname of the KOS root directory."""
    global _kos_root
    if _kos_root: return _kos_root
    ...

备注

  • 即使字符串只有一行,也使用三重引号。这使得以后更容易扩展它。
  • 闭合引号与开引号在同一行。这对于单行 Docstring 来说看起来更好。
  • Docstring 前后都没有空行。
  • Docstring 是一个以句点结尾的短语。它将函数或方法的效果规定为命令(“执行此操作”,“返回彼值”),而不是描述;例如,不要写“返回路径名……”。
  • 单行 Docstring 不应是重述函数/方法参数的“签名”(可通过内省获取)。不要这样做:
    def function(a, b):
        """function(a, b) -> list"""
    

    这种类型的 Docstring 仅适用于 C 函数(例如内置函数),其中无法进行内省。然而,返回值的性质不能通过内省确定,因此应该提及。这种 Docstring 的首选形式是:

    def function(a, b):
        """Do X and return a list."""
    

    (当然,“执行 X”应该被有用的描述替换!)

多行 Docstring

多行 Docstring 包含一个摘要行(就像单行 Docstring 一样),然后是一个空行,然后是更详细的描述。摘要行可能被自动索引工具使用;重要的是它必须在一行内,并与 Docstring 的其余部分通过一个空行隔开。摘要行可以与开引号在同一行,也可以在下一行。整个 Docstring 的缩进与第一行的引号相同(见下面的示例)。

在所有文档说明类的 Docstring(单行或多行)之后插入一个空行——一般来说,类的各个方法之间用一个空行分隔,并且 Docstring 需要与第一个方法之间有一个空行。

脚本(独立程序)的 Docstring 应该可用作其“用法”消息,当脚本以不正确或缺少参数(或可能带有“-h”选项,表示“帮助”)调用时打印。这样的 Docstring 应该记录脚本的功能和命令行语法、环境变量以及文件。用法消息可以相当详细(几屏内容),并且应该足以让新用户正确使用命令,以及为高级用户提供所有选项和参数的完整快速参考。

模块的 Docstring 通常应该列出模块导出的类、异常和函数(以及任何其他对象),并对每个进行单行摘要。(这些摘要通常比对象 Docstring 中的摘要提供更少的细节。)包的 Docstring(即包的 __init__.py 模块的 Docstring)也应该列出包导出的模块和子包。

函数或方法的 Docstring 应该总结其行为并记录其参数、返回值、副作用、引发的异常以及何时可以调用它的限制(如果适用)。应该指明可选参数。应该记录关键字参数是否是接口的一部分。

类的 Docstring 应该总结其行为并列出公共方法和实例变量。如果类旨在被子类化,并且为子类提供了额外的接口,则应单独列出此接口(在 Docstring 中)。类构造函数应在其 __init__ 方法的 Docstring 中进行文档说明。各个方法应由其自己的 Docstring 进行文档说明。

如果一个类继承自另一个类,并且其行为大部分继承自该类,其 Docstring 应该提及这一点并总结差异。使用动词“override”(覆盖)来表示子类方法替换超类方法且不调用超类方法;使用动词“extend”(扩展)来表示子类方法调用超类方法(除了其自身行为之外)。

在正文中,**不要**使用 Emacs 的约定,即用大写字母提及函数或方法的参数。Python 是大小写敏感的,参数名称可以用作关键字参数,因此 Docstring 应该记录正确的参数名称。最好将每个参数列在一单独的行上。例如:

def complex(real=0.0, imag=0.0):
    """Form a complex number.

    Keyword arguments:
    real -- the real part (default 0.0)
    imag -- the imaginary part (default 0.0)
    """
    if imag == 0.0 and real == 0.0:
        return complex_zero
    ...

除非整个 Docstring 都适合在一行内,否则将闭合引号单独放在一行上。这样,Emacs 的 fill-paragraph 命令就可以对其进行操作。

处理 Docstring 缩进

Docstring 处理工具将从 Docstring 的第二行及后续行中去除统一数量的缩进,该数量等于第一行之后所有非空行的最小缩进。Docstring 第一行(即直到第一个换行符)的任何缩进都是无关紧要的并被移除。Docstring 后续行的相对缩进得以保留。空行应从 Docstring 的开头和结尾移除。

由于代码比文字更精确,这里是算法的实现:

def trim(docstring):
    if not docstring:
        return ''
    # Convert tabs to spaces (following the normal Python rules)
    # and split into a list of lines:
    lines = docstring.expandtabs().splitlines()
    # Determine minimum indentation (first line doesn't count):
    indent = sys.maxsize
    for line in lines[1:]:
        stripped = line.lstrip()
        if stripped:
            indent = min(indent, len(line) - len(stripped))
    # Remove indentation (first line is special):
    trimmed = [lines[0].strip()]
    if indent < sys.maxsize:
        for line in lines[1:]:
            trimmed.append(line[indent:].rstrip())
    # Strip off trailing and leading blank lines:
    while trimmed and not trimmed[-1]:
        trimmed.pop()
    while trimmed and not trimmed[0]:
        trimmed.pop(0)
    # Return a single string:
    return '\n'.join(trimmed)

此示例中的 Docstring 包含两个换行符,因此长度为 3 行。第一行和最后一行是空白行:

def foo():
    """
    This is the second line of the docstring.
    """

为了说明:

>>> print repr(foo.__doc__)
'\n    This is the second line of the docstring.\n    '
>>> foo.__doc__.splitlines()
['', '    This is the second line of the docstring.', '    ']
>>> trim(foo.__doc__)
'This is the second line of the docstring.'

修剪后,这些 Docstring 是等价的:

def foo():
    """A multi-line
    docstring.
    """

def bar():
    """
    A multi-line
    docstring.
    """

致谢

“规范”文本主要来自 Guido van Rossum 的 PEP 8

本文档借鉴了 Python Doc-SIG 档案中的思想。感谢所有过去和现在的成员。


来源:https://github.com/python/peps/blob/main/peps/pep-0257.rst

最后修改:2024-04-17 11:35:59 GMT