如何规范书写文档说明(Docstring) -- PEP 257


正文

  • 引言
  • 理论基础
  • 详细说明
    • 什么是文档说明
    • 单行的文档说明
    • 多行的文档说明
    • 处理文档说明缩进格式
  • 参考和补充说明
  • 版权
  • 鸣谢

引言

这个PEP文件是关于Python文档说明的书写语义和约定。

理论基础

这个PEP协议的目的是标准化文档说明的高级结构:里面有个包含说明,怎么去描述(不在其内创建任何的标记语法)。这个PEP秀逸包含约定,而不是法规或语法。


"有个通用的约定应该是可维护的、清晰可懂的、满足一致性的,同时也应该是好的编程习惯的基础。它不会违背你的意愿来强制要求你遵循那些规则。这就是Python!" -- Tim Peter写于comp.lang.python,2001-06-16

不按照约定来书写,最差的结果是你写的代码会比较难看,不美观。同时有些软件对约定(规范)比较重视,遵循这些规范才能得到好的结果。

详细说明
什么是文档说明?

一个文档说明是一个字符串,它出现在一个模块,函数,类或方法的定义的第一个语句。这样的文档说明即为该对象的__doc__特殊属性。

所有的模块,或对于被一个模块导入的函数和类都应该有文档说明。公共方法(包括__init__构造函数)也应该有文档说明。一个包可以在其包目录下存放其(模块的文档说明)init.py文件。

说明字符串通常出现在Python代码中的任意位置,这个代码也可以看做文档。他们既不能由Python编译器识别,也无法向运行时的对象属性那些被访问(即不分配给__doc__),但两种额外的文档说明,可以通过软件工具提取:

  1. 在一个模块、类或__init__方法的顶层的一个简单申明后立即出现的字符串--“属性文档说明”
  2. 在其他文档说明后立即出现的字符串--“补充文档说明”

想获取关于属性和补充文档说明的详细描述,请查阅PEP 258,"Docutils Design Specification"(文档工具设计说明)

XXX 提及的2.2版本的文档说明特性

为了满足一致性,常用3个双引号"""quotes"""来包裹文档说明。如果你在文档说明里使用了反斜杠\,使用r"""quotes""""来包裹。对于那些使用了Unicode文档说明的,使用u""""quotes"""来包裹。

有2种形式的文档说明:单行和多行文档说明。

单行文档说明

单行的说明文档是十分明显的一种类型。将说明描述字符串写入一行即可。比如说:

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

说明:

  • 三个引号使用频繁,即便字符串可以写在一行内。这易于后期扩展。
  • 单行的3个双引号应在一行,看上去更美观
  • 在文档说明字符串前后没有空行
  • 文档说明应以句号结尾的一段语句。它以一个命令规定了函数或方法的结果,而不是描述;例如,不要写“Returns the pathname ...”
  • 单行文档说明不应该时一个"说明"去重申函数/方法的参数。不要像这样:
def function(a, b):
    """function(a, b) -> list"""

上面的这种类型的文档说明只适用于c函数(例如内建函数)这样的无法内省的函数。然而,return值的类型无法由内省决定,因此这需要被注意。对于这种文档说明较好的形式应该是:

def function(a, b):
    """Do X and return a list."""
多行文档说明

多行文档说明包含一个概要行(如单行文档说明那样),然后接一个空行,然后是更详细的说明。这种概要行应该使用动态索引工具来使用;让它在一行显示是十分重要的,并且使用空行来与其他的文档说明分割开。这个概要行可能与右边的3个双引号在同一行或在下一行。整个文档说明跟第一行那样缩进排版。

在所有的文档说明后插入一个空白行(一行或多行),类文档——一般来说,类的方法是由一个单一的空行隔开,文档说明需要有一个空行来开始第类的一个方法。

当一个脚本调用时使用了不正确或缺少参数(或是一个“H”选项,在“帮助”),其文档说明(一个独立的程序)应打印其使用方法信息。这样的文档说明应该包含脚本的功能和命令行语法、环境变量和文件。使用信息可以相当详细(有几个屏幕满),对于新用户正确使用命令,以及对高级用户的所有选项和参数的完正的快速引用应该足够了。

一个模块的文档说明一般应列出由模块导入的类,异常和功能(以及任何其他对象),并对应的使用一个单行的概要。(这些概要一般会比对象的文档说明提供更少的细节)。一个包的文档说明(即包的__init__ .py模块的文档说明),还应该列出由包导入的的模块和子包。

一个函数或方法的文档说明应该总结其行为和记录其参数,返回其值(S),附带作用,抛出的异常和调用时的限制(所有这些如果适用)。可选参数应被表示。无论关键字参数是否为接口的一部分它应该记录。

一个类的文档说明应该总结其行为并列出其公共方法和实例变量。如果这个类是一个子类,有额外的接口,该接口应分别列出(在文档字符串)。类的构造函数应该记录在文档说明的__init__方法。单独的方法应该由自己的文档说明记录。

如果一个类的子类及其行为主要是继承自该类,它的文档说明应该提到这点并总结其差异。用动词“override”表明一个类方法代替父类的方法并且它不调用父类的方法;用动词“extend”,表示一个子类的方法调用父类的方法(除了它自己的行为)。

不要在运行的文本中使用Emacs的约定方法大写函数或方法的参数。Python是大小写敏感,并且参数名可以使用关键字参数,所以文档说明应该记录正确的参数名。最好是在一个单独的行中列出每个参数。例如:

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
    ...

除非整个文档说明在一行中,否则将后面的引号单独放一行。可以使用Emacs的fill-paragraph命名创建中格式。

处理文档说明的缩进

文档说明处理工具将文档说明的第二行和之后的行的缩进除去,等于将第一行后的所有非空白行的碎金最小化。第一行的任意缩进(即到第一个换行符)是不明显的,要被删除的。文档说明的后面的行的相对缩进保留。空白行应该从文档的开始和结束处删除。

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

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.maxint
    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.maxint:
        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)

在这个例子中的文档说明串包含两个换行符并因此有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.'

下面的2个函数的文档说明是一致的:

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

def bar():
    """
    A multi-line
    docstring.
    """
参考和补充说明
序号说明及连接
[1]PEP 256, Docstring Processing System Framework, Goodger (http://www.python.org/dev/peps/pep-0256/)
[2](1, 2) PEP 258, Docutils Design Specification, Goodger (http://www.python.org/dev/peps/pep-0258/)
[3]http://docutils.sourceforge.net/
[4]http://www.python.org/dev/peps/pep-0008/
[5]http://www.python.org/sigs/doc-sig/
版权

本文档在公共域中存放

鸣谢

这个“规范”的文字大多来自于Python Style Guide[4],由Guido van Rossum编写。

本文借鉴了Python Doc-SIG [5]文档。感谢过去和现在的所有成员。

来源:https://github.com/python/peps/blob/master/pep-0257.txt


本文是https://www.python.org/dev/peps/pep-0257/一文的中文翻译版,由castiel-Lu翻译,水平有限,翻译的可能有些问题,但应该不影响阅读。本文可以自由转载,不对之处希望可以email我(18367826960@163.com) -- 2017-10-17


转载于:https://my.oschina.net/LuCastiel/blog/1552148

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值