PEP 257 -- Docstring 约定 (翻译)

PEP:257
Title:Docstring Conventions
Author:David Goodger, Guido van Rossum
Discussions-To:doc-sig at python.org
Status:Active
Type:Informational
Created:29-May-2001
Post-History:13-Jun-2001

Contents:

目录

Abstract:

Rationale

Specification

什么是Docstring?

单行docstrings

多行docstrings

处理Docstrings缩进

Reference and footnotes:

Acknowledgements


Abstract:

这个PEP文档记录了Pythn docstrings相关的语义和准则

Rationale

本PEP的目标旨在标准化docstrings的高水平结构:它们应该包含什么,以及怎么写它(不涉及docstrings内的任何语法)。本PEP包含准则,但是不是法律或者语法。

“一个统一的准则关系到代码的可维护性、清晰性、一致性和良好编码习惯的基础。它不做的是让你一定要这么做,这就是Python!”

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

如果你违反这些准则,最差也就是看上去丑一点。但是有些软件(比如Docutils docstring处理系统)可能会意识到这些准则,所以使用这些准则会让你得到最佳的结果。

Specification

什么是Docstring?

一个docstring是一个string literal,作为模块、函数、类或者方法定义的第一个陈述。这样一个docstring就成为了一个对象的特殊属性__doc__。

所有的模块应该有docstrings,所有由模块输出的函数和类都应该有docstrings。公共方法(包括__init__构造器)也应该有docstrings。一个包可能由包目录下面的__init__.py文件里面模块docstring归档。

在Python代码中其它地方的string literals也可能作为文档。他们不会被Python字节码编译器识别,也不能作为运行时对象属性进行访问(也就是没有赋值给__doc__),但是两类额外的docstrings可能被软件工具提取。

  1. string literals出现在一个模块、类或者__init__方法的顶层,一个简单赋值的后面的叫做“attribute docstrings”。
  2. string literals出现在另一个docstrings后面的叫做“additional docstrings”。

请看PEP258,“Docutils设计规范”,查看属性docstrings和额外docstrings的详细描述。

为了一致性,一直使用"""三双引号"""来写docstrings。如果在docstrings里面使用任意的反斜杠,用r"""raw triple double quotes"""。如果用Unicode docstrings,用u"""Unicode triple-quoted strings"""。

有两种形式的docstrings,一种是单行docstrings,另一种是多行docstrings。

单行docstrings

单行适用于非常明显的可以用单行的场景。比如:

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

注意点:

  • 使用三双引号,即使只是单行。这使得将来的扩展变得很容易。
  • 开闭三双引号都在同一行。
  • docstrings前后没有空行
  • 单行docstrings是一个句号结尾的短语。它以命令的形式("Do this", "Return that")而不是描述的形式(Returns the pathname...) prescribe了函数或者方法的效果。
  • 单行docstring不应该作为重申函数或者方法的参数的“签名”(这一点可以通过introspection做到)。不要做:
def function(a, b)
    """function(a, b) -> list"""

这种类型的docstrings只适用于C函数(比如built-ins),因为这时候introspection不可用。但是返回值的特性不能通过introspection得到,所以应该在docstrings里面提到。所以比较推荐的这样的docstrings形式是:

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

多行docstrings

多行docstrings由像单行docstrings的一组概要行,一个空行和一个更加详细的描述组成。概要行可能会被自动索引工具使用。它单独成行,然后由一个空行和剩下的内容分割,这样的形式安排很重要。概要行可以是在开三双引号这一行,也可以在它的下一行。整个docstrings都像第一个开三双引号这样的缩进(详见下文例子)。

如果是document一个类,在单行docstrings或者多行docstrings后面添加一个空行。也就是类的方法需要由一个空行分割,docstrings需要和第一个类的方法通过一个空行分隔。

一个脚本的docstrings应该可以被当作“usage”消息使用。“usage”消息是在脚本使用的时候没有用正确的或缺失的参数的时候打印出来的(或者可能是通过一个“-h”选项)。这样一个docstring应该归档脚本的函数、命令行语法、环境变量和文件。usage可以是相当详细的并且足够一个新用户来合适的使用命令,并且对于有经验的用户可以作为一个快速的所有选项和参数的快速reference。

一个模块的docstrings通常应该列出模块输出的类、异常和函数(以及任何其它对象),每一个一个单行概要。通常这些概要不需要像对象本身的docstring那么详细。一个包的docstrings(也就是__init__.py模块的docstrings)应该列出这个包输出的模块和子包。

函数或者方法的docstrings应该总结总结它的行为,归档它的参数、返回值,副作用,异常,以及使用的约束。可选参数应该表明。无论关键词参数是不是接口的一部分,都应该归档。

类的docstrings应该总结它的行为,列出公共方法和实例变量。如果这个类可能要被作为子类,并且由额外的子类的接口,这个接口也应该独立的列出来(在docstrings里面)。类构造器应该在__init__方法的docstrings里面进行归档。其它独立的方法应该在各自的docstrings里面进行归档。

如果一个类是另一个类的子类,并且它的行为和另一个子类很像。那么这个类的docstrings应该总结这一点,并且总结它们的差异。用“override”这个词来表示一个子类方法替换父类方法,并且不调用父类方法。除了自身行为之外,使用“extend”这个词来表示子类方法调用父类方法。

不要在运行文本中用大写来表示函数或者方法的参数(Emacs中的准则)。Python是大小写敏感的,参数名可以被用来作为关键词参数。所以docstrings可以用来归档正确的参数名。最好在独立的行里面列出每个参数,比如:

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


除非整个docstrings就是一行,否则的话,将闭三双引号单独成行。这样的话,Emacs的fill-paragraph命令就可以用了。

处理Docstrings缩进

Docstrings处理工具会在docstrings从第二行开始直到最后一行剥离统一数量的缩进。直到和下文最小缩进一致。docstrings第一行的任意的不必要的缩进都会被剥离。docstrings中后面部分的相对缩进被保留。开头和结尾的空行应当被移除。

因为代码比文字更加准确,下面是这个算法实现的代码:

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

下面这个docstrings的例子包含两个换行符,因此有三行。第一行和最后一行是空行。

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.

一旦修剪了,那么下面两个形式的docstrings就是等价的。

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

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

Reference and footnotes:

[1]PEP 256, Docstring处理系统框架,Goodger
[2]PEP 258, Docutils设计规范,Goodger
[3]

http://docutils.sourceforge.net/

[4]http://www.python.org/dev/peps/pep-0008/
[5]http://www.python.org/sigs/doc-sig/

这个文档放在public domain

Acknowledgements

The "Specification" text comes mostly verbatim from the Python Style Guide [4] essay by Guido van Rossum.

This document borrows ideas from the archives of the Python Doc-SIG [5]. Thanks to all members past and present.

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值