每日10行代码123: 编写高质量python代码的方法49:为每个函数、类和模块编写文档字符串

由于Python 是一门动态语言,所以文档显得极其重要。Python 对文档提供了内置的支持,使得开发者可以把文档与代码块关联起来。与其他许多编程语言不同,Python程序在运行的时候,能够直接访问源代码中的文档信息。
例如:在为函数编写了def 语句之后,我们可以紧接着提供 docstring, 以便将一段开发文档与该函数关联起来:

def palindrome(word):
    """Return True if the given word is a palindrome."""
    return word == word[::-1]

在 Python 程序中,我们可以通过名为 __doc__ 的特殊属性,来访问该函数的文档。

print(repr(palindrome.__doc__))
>>>
'Return True if the given word is a palindrome.'

函数、类和模块,都可以与文档字符串相关联。系统会在编译和运行 Python 程序的过程中,维护这种联系。因为 Python 代码支持文档字符串和 __doc__ 属性,所以产生了下面三个好处:

  • 由于能够访问代码中的文档,所以交互式开发变得更加方便了。我们可以用内置的 help 函数来查看函数、类和模块的文档,也可以更加方便地采用互动式 Python 解释器 (也就是Python shell、Python “壳”)及IPython Notebook(http://ipython.org) 之类的工具来开发算法、测试 API 并编写代码片段。
  • 这种标准的文档定义方式,使得开发者很容易就能构建出一些工具,把纯文本转换成HTML 等更友好的格式。例如,Python 开发者社区就构建了 Sphinx等优秀的文档生成工具。此外,还有像 Read the Docs 这样,由python社区协力搭建的网站,能够为开源的Python 项目提供美观的文档及免费的存放空间。
  • 由于 Python 将文档视为第一等级的 (first-class) 对象,而且可以令开发者在程序中访问格式良好的文档信息,所以我们乐意编写更多文档。 Python 社区的开发者都坚信:文档是非常重要的。代码必须要有完备的文档,才能称上是好代码 。由于有了这一信息,所以大部分开源的Pyhon库,都应该会带有优雅的文档。
    为了融入这种良好的文档撰写氛围,我们在编制文档字符串时,应该遵循一些规范。对细节问题的详细讨论,参阅 PEP 257. 下面这几条规范,是大家都应该遵守的。

1. 为模块编写文档

每个模块都应该有顶级的docsting. 这个字符串字面量,应该作为源文件的第一条语句 。开发者应该在字符串两端,使用三重双引号(""")把它括起来。之所以要编写 docstring ,是为了介绍当前这个模块,以及模块之中的内容。
docstring 的头一行文字 ,应该是一句话,用以描述本模块的用途。它下面那段话,应该包含一些细节信息,把与本模块的操作有关的内容,告诉模块的使用者。我们还可以在模块的 docstring 中,强调本模块里面比较重要的类和函数,使得开发者能够据此了解该模块的用法。
下面列举一个模块级别的 docstring:

# words.py
#!/usr/bin/env python3
"""Library for testing words for various linguistic patterns.

Testing how words relate to each other can be tricky sometimes!
This moudle provides easy ways to determine when words you've 
found have special properties.

Available functions:
- palindrome: Determine if a word is a palindrome.
- check_anagram: determine fi two words are anagrams.
...
"""

#...

如果该模块是个命令行工具,那我们可以考虑把工具的用法,写在本模块的docstring里面,以便告诉用户应该如何 从命令行里运行这个工具。

2.为类编写文档

每个类都应该有类级别的 docstring, 它的写法与模块级的 docstring 大致相同。头一行,也是用一句话来阐明本类的用途。接下来,用一段话来详述该类的操作方式。
类中比较重要的 public 属性及方法,也应该在这个 docstring 里面加以强调。此外,还应该告诉子类的实现者,如何才能正确地与protected 属性( 参见该书第27条) 及超类方法相交互。
下面示范一个类级别的 docstring:

Library for testing words for various linguistic patterns.

Testing how words relate to each other can be tricky sometimes!
This moudle provides easy ways to determine when words you've 
found have special properties.

Available functions:
- palindrome: Determine if a word is a palindrome.
- check_anagram: determine fi two words are anagrams.

#...

3. 为函数编写文档

每个public函数及方法,都应该有 docstring, 其写法,与模块和类级别的 docstring 相似。第一行,还是用一句话来描述本函数的功能。接下来,用一段话描述具体的行为和函数的参数。若函数有返回值,则应该在docstring 中写明。如果函数可能抛出某些调用者必须处理的异常,而这些异常又是函数接口的一部分,那么 docstring 应该对其进做出解释 。
下面演示函数级别的 docstring:

def find_anagrams(word, dictionary):
    """Find all anagrams for a word.

    This function only runs as fast as the test for 
    membership in the 'dictionary' container. It will
    be slow if the dictionary is a list and fast if
    it's a set.

    Args:
        word: String of the target word.
        dictionary: Container with all strings that
            are known to be acctual words.

    Returns:
        List of anagrams that were found. Empty if 
        none were found.
    """
    #...

对函数撰写 docstring 时,还有一些特例,大家应该了解:

  • 如果函数没有参数,且仅有一个简单的返回值,那么,只需用一句话来描述该函数,应该就够了。
  • 如果函数根本没就没有返回值 ,那么最好别在 docstring 里面提到它,也就是说,不要在 docstring 里面出现 “returns None” 这样的说法。
  • 如果函数在正常的使用过程中不会抛出异常,那就不要在 docstring 里面提到异常。
  • 如果函数接受数量可变的位置参数(参见该书第18条) 或数量可变的关键字参数 (参见该书第19条),那就应该在文档的参数列表中,使用 *args 和 **kwargs 来描述它们的用途。
  • 如果函数 的参数有默认值,那么就应该指出这些默认值(参见该书第20条)。
  • 如果函数是个生成器(参见该书第16条),那么应该描述该生成器在迭代时所产生的内容。
  • 如果函数是个协程(参见该书第40条),那么应该描述该协程会于何时停止迭代。

小提示:为模块编写 docstring 之后 ,一定要保证文档的及时更新。

要点:

  • 我们应该通过docstring, 为每个模块、类和函数编写文档。在修改代码的时候,应该更新这些文档。
  • 为模块撰写,应该介绍本模块的内容,并且要把用户应该了解的重要类及重要函数列出来。
  • 为类撰写文档时,应该在calss语句下面的 docstring 中,介绍本类的行为、重要属性,以及本类的子类应该实现的行为。
  • 为函数及方法撰写文档时,应该在def 语句下面的 docstring 中,介绍函数的每个参数 ,函数的返回值,函数在执行过程中可能抛出的异常,以及其他行为。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值