PEP 0257 -- Docstring 約定

2021-02-23 Python程式設計師


Python部落(www.freelycode.com)組織翻譯, 禁止轉載


概要

本篇PEP文檔主要對Python函數文檔字符串的語義和規範進行了相關闡述。

基本原理

PEP的目標是讓程序猿寫出的Python函數文檔字符串(Doctring)高度結構化、規範化:文檔字符串應該包含什麼,如何書寫(在文檔字符裡避免使用標記語法的情況下)。 PEP中包含的是約定俗成的東西,不是定律或嚴苛的語法。

一個通用的公約給編程提供了可維護性,清晰性,一致性,同時也提供了良好的編程習慣的基礎。但它從來不會強迫你去按照它的標準做你不喜歡的事情。這就是Python!」

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

如果你不按約定編寫代碼,最壞的情況是,寫出來的代碼很邋遢。但有些軟體代碼的編寫必須按照約定來(比如 Docutils [3] docstring 的處理系統[1] [2] )。總而言之,遵守約定,能給你帶來最好的結果。.

詳述

什麼是 Docstring?

Docstring是模塊、類、方法中的第一個聲明性描述說明。比如docstring變成 __doc__ 類的special attribute of that object.

所有的modules一般都有Docstring,模塊中的類和方法也應該有Doctring。公共方法 (包含 __init__ 構造器的方法) 也應該有Doctring。一個包的描述信息一般在包目錄中文件__init__.py的Doctring中。

字符串類說明信息在Python代碼中隨處可見,通常用稱為文檔說明的一部分。這些信息不會被Python字節碼編譯器識別到,也不能被運行時對象屬性訪問。但是,有兩類附加的docstring能被軟體工具提取出來。

1. 在一個模塊、類或者__init__ 方法中一開始就出現的字符串描述信息,我們稱之為 "attribute docstrings"。

2. 緊跟在一個 docstring 後面的字符串描述信息,被稱為 "additional docstrings"。

請參考 PEP 258 , "Docutils Design Specification" [2] ,裡面有關於"attribute docstrings"和"additional docstrings"的詳細說明。

下面是三種情況下,Docstring的一般寫法:

正常情況下: """三個雙引號""" (單純用三個雙引號引起來)

如果有反斜線: r"""raw triple double quotes"""  (在開頭加字幕r)

如果使用統一字符編碼標準:u"""Unicode triple-quoted strings""" . (在開頭加字幕u)

一共有兩種Docstring,單行的和多行的:

單行 Docstrings

單行的字符串文檔是最常見的,比如:

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

內省機制:Python的內省機制還是比較強大的。所謂內省,實際上主要是指在runtime獲得一個對象的全部類型信息。這樣可以提供更好的編程靈活性。

這種類型的文檔字符串只適合C函數(比如內嵌函數),因為C中沒有自省的機制。然而,返回值的類型不能通過內省確定,因此應在Docstring中加以說明。因此,文檔字符串的首選形式是這樣的:

def function(a, b):

    """Do X and return a list."""

(Of course "Do X" should be replaced by a useful description!)

多行 Docstrings

多行 docstrings 首先包含一個概述行,緊跟著空一行,然後跟著更加詳細的描述信息。概述行會被自動索引工具識別並處理,所以概述行必須是獨自佔用一行且和後續描述間空一行。概述行可以和開始的雙引號在一行,也可以另起一行,獨佔第二行。整個Docstring的縮進都應該和第一行保持一致 (可以參考下面的例子)。

通常,在給一個類做文檔注釋時,在所有Docstring(單行和多行)的末尾插入一個空行,類的每個方法之間由一個空行分隔開,所以,需要在Docstring跟第一個方法之間留一個行空行。

一個獨立可運行的腳本中的Docstring應當包含該腳本的使用說明信息。 調用腳本的過程中,如果參數用錯或缺失,應能夠列印錯誤信息 (或者用於 "-h" 選項,用來顯示幫助信息).。這樣的 docstring 應該描述出腳本的功能、命令行語法、環境變量和文件信息。 使用說明應儘可能詳細和充分,能夠指導新用戶正確的使用腳本,同時對於高級用戶而言,也應在該Docstring裡獲取到這個腳本的所有選項和參數說明。

一個模塊的docstring應該列出該模塊能夠輸出的類、異常、方法 (以及其他的一些對象)的對應簡述信息,每個對象的描述獨佔一行。 一個包的docstring(比如docstring of the package's __init__.py module) 應該列出包的模塊清單和子包清單。

一個方法的docstring應該簡述它的功能、參數、返回值和類型、異常、約束等。還有可選參數。還應說明這些關鍵字參數是否屬於接口的一部分。 

一個類的docstring應該包含這個類的功能概述、公共方法清單、實例變量清單。如果這個類設計的可以作為父類,而且給子類預留了相應的接口,那麼,這個接口應該在docstring中單獨列出。除此以外,這個類的構造方法的文檔信息應該在 __init__ 方法的docstring中表述。具體到方法的話,各自應該有自己的docstring。

如果一個類是另一個類的子類,而且這個類的幾乎完全繼承了父類,那麼要在它的docstirng中應該提到這些信息,以及與父類的不同之處。使用動詞 "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前後的空白行不應保留。

代碼比語言更精準,下面是這個算法的實現: 

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)

樣例中的docstring包含兩個換行符,因此長度為3行。第1行和第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.

    """

英文原文: https://www.python.org/dev/peps/pep-0257/

譯者: cg2580

相關焦點

  • python筆記30-docstring注釋添加變量
    docstring也就是給代碼加注釋的內容了,python可以給函數,類、方法,模塊添加注釋內容,注釋標準格式一般是三個雙引號(或三個單引號)docstring先看一個簡單案例,在函數裡面添加注釋內容,函數下方三個雙引號裡面就可以寫該函數的注釋文檔了,如果需要調用此函數的注釋內容# coding:utf-8def yoyo():    """函數功能:列印hello
  • 為什麼 Python 的 f-string 可以連接字符串與數字?
    但是,由於我們已知 Python 是強類型語言,已知數字類型絕對不可能直接拼接到字符串裡,因此,只能說明 f-string 語法在底層作了某種類型轉化的操作!那麼,我們就可以再提出一個新的問題:f-string 語法在處理字符串與數字時,是如何實現數字的類型轉化的呢?
  • python辦公自動化(二) | 讀取.txt、.data、.doc和.docx文檔的部分內容
    alltxt[alltxt.index(s_txt):alltxt.index(e_txt)+len(e_txt)]find(substr, beg=0, end=len(string))index(substr,beg=0,end=len(string)) 同find()類似,不同的是,如果未找到substr,則返回一個異常 ValueError: substring not found。
  • 利用Doc2Vec 對 Quora 問題標籤聚類
    翻譯 | nick李、csnoooong 校對 | 凡江 整理 | 志豪原文連結:https://medium.com/@samriddhisinha/clustering-quora-question-tags-with-doc2vec-d4fb3c5177f7
  • 動員講話 Pep talk
    請看外電的報導:He was asked to give a pep talk to England's soccer team for its World Cup qualifying match (he politely declined) and to offer campaign tips to embattled
  • 從String類型發散想到的一些東西
    值類型表示存儲在棧上的類型,包括簡單類型(int、long、double、short)、枚舉、struct定義;引用類型表示存在堆上的類型,包括數組、接口、委託、class定義;string 是引用類型字符特殊性
  • int切片和string切片為什麼不能轉為interface類型的切片
    如:cannot use (type []string) as type []interface {}和cannot use (type []int) as type []interface {}等。所以, 特地寫下這篇文章用來時時刻刻地提醒自己。Q1:可以將[]T轉為[]interface{}類型嘛?
  • 一課一練:pep六年級上冊unit6partC,附答案
    前面的內容:一課一練:pep六年級上冊unit1partA,附答案一課一練:pep六年級上冊unit1partB,附答案一課一練:pep六年級上冊unit1partC,附答案 一課一練:pep六年級上冊unit1測試卷,附答案一課一練:pep六年級上冊unit2partA,附答案一課一練:pep六年級上冊
  • String、StringBuilder、StringBuffer,誰性能最高?
    此外,還有stringbuilder等這些類的輔助,那麼本文就從String,StringBuiler和StringBuffer的區別開始,去探討Java中的字符串操作。            str += i;        }        System.out.println("執行"+count+"次  String 耗時:"+ getRunTime(startTime));        startTime = System.currentTimeMillis();        StringBuilder stringBuilder
  • 一課一練:pep六年級上冊unit4partC,附答案
    CDFABE前面的內容:一課一練:pep六年級上冊unit1partA,附答案一課一練:pep六年級上冊unit1partB,附答案一課一練:pep六年級上冊unit1partC,附答案 一課一練:pep六年級上冊unit1測試卷,附答案一課一練:pep六年級上冊unit2partA,附答案
  • C++ string 類詳解
    string 類定義隱藏了字符串的數組性質,讓我們可以像處理普通變量那樣處理字符串。string 對象和字符數組之間的主要區別是:可以將 string 對象聲明為簡單變量,而不是數組。1.1 string 類幾種常見的構造函數:1)string(const char *s) :將 string 對象初始化為 s 指向的字符串2)string(size_type n,char c) :創建一個包含 n 個元素的 string 對象,其中每個元素都被初始化為字符 c3)string(const
  • STL string容器用法
    C++的算法庫對string類也有著很好的支持,並且string類還和c語言的字符串之間有著良好的接口。string概念string和char*的比較string是一個類, char*是一個指向字符的指針。