{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 函数的文档" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "你在调用函数的时候,你像是函数这个产品的用户。\n", "\n", "而你写一个函数,像是做一个产品,这个产品将来可能会被很多用户使用 —— 包括你自己。\n", "\n", "产品,就应该有产品说明书,别人用得着,你自己也用得着 —— 很久之后的你,很可能把当初的各种来龙去脉忘得一干二净,所以也同样需要产品说明书,别看那产品曾经是你自己设计的。\n", "\n", "Python 在这方面很用功,把函数的 “产品说明书” 当作语言内部的功能,这也是为什么 Python 有 [Sphinx](http://www.sphinx-doc.org) 这种工具,而绝大多数其他语言没有的原因之一罢。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Docstring" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "在函数定义内部,我们可以加上 **Docstring**;将来函数的 “用户” 就可以通过 `help()` 这个内建函数,或者 `.__doc__` 这个 Method 去查看这个 Docstring,即,该函数的 “产品说明书”。\n", "\n", "先看一个 Docstring 以及如何查看某个函数的 Docstring 的例子:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on function is_prime in module __main__:\n", "\n", "is_prime(n)\n", " Return a boolean value based upon\n", " whether the argument n is a prime number.\n", "\n", "\n", " Return a boolean value based upon\n", " whether the argument n is a prime number.\n", " \n" ] }, { "data": { "text/plain": [ "'\\n Return a boolean value based upon\\n whether the argument n is a prime number.\\n '" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def is_prime(n):\n", " \"\"\"\n", " Return a boolean value based upon\n", " whether the argument n is a prime number.\n", " \"\"\"\n", " if n < 2:\n", " return False\n", " if n == 2:\n", " return True\n", " for m in range(2, int(n**0.5)+1):\n", " if (n % m) == 0:\n", " return False\n", " else:\n", " return True\n", "\n", "\n", "help(is_prime)\n", "print(is_prime.__doc__)\n", "is_prime.__doc__" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Docstring 可以是多行字符串,也可以是单行字符串:" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on function is_prime in module __main__:\n", "\n", "is_prime(n)\n", " Return a boolean value based upon whether the argument n is a prime number.\n", "\n", "Return a boolean value based upon whether the argument n is a prime number.\n" ] }, { "data": { "text/plain": [ "'Return a boolean value based upon whether the argument n is a prime number.'" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def is_prime(n):\n", " \"\"\"Return a boolean value based upon whether the argument n is a prime number.\"\"\"\n", " \n", " if n < 2:\n", " return False\n", " if n == 2:\n", " return True\n", " for m in range(2, int(n**0.5)+1):\n", " if (n % m) == 0:\n", " return False\n", " else:\n", " return True\n", "\n", "\n", "help(is_prime)\n", "print(is_prime.__doc__)\n", "is_prime.__doc__" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Docstring 如若存在,必须在函数定义的内部语句块的开头,也必须与其它语句一样保持相应的缩进(Indention)。Docstring 放在其它地方不起作用:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on function is_prime in module __main__:\n", "\n", "is_prime(n)\n", "\n", "None\n" ] } ], "source": [ "def is_prime(n):\n", " if n < 2:\n", " return False\n", " if n == 2:\n", " return True\n", " for m in range(2, int(n**0.5)+1):\n", " if (n % m) == 0:\n", " return False\n", " else:\n", " return True\n", " \"\"\"\n", " Return a boolean value based upon\n", " whether the argument n is a prime number.\n", " \"\"\"\n", "\n", "help(is_prime)\n", "print(is_prime.__doc__)\n", "is_prime.__doc__" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 书写 Docstring 的规范" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "规范,虽然是人们最好遵守的,但其实通常是很多人并不遵守的东西。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "既然学,就要**像样** —— 这真的很重要。所以,非常有必要认真阅读 Python [PEP 257](https://www.python.org/dev/peps/pep-0257/) 关于 Docstring 的规范。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "简要总结一下 PEP 257 中必须掌握的规范:\n", "\n", "> 1. 无论是单行还是多行的 Docstring,一概使用三个双引号括起;\n", "> 2. 在 Docstring 内部,文字开始之前,以及文字结束之后,都不要有空行;\n", "> 3. 多行 Docstring,第一行是概要,随后空一行,再写其它部分;\n", "> 4. 完善的 Docstring,应该概括清楚以下内容:参数、返回值、可能触发的错误类型、可能的副作用,以及函数的使用限制等等;\n", "> 5. 每个参数的说明都使用单独的一行……\n", "\n", "由于我们还没有开始研究 Class,所以,关于 Class 的 Docstring 应该遵守什么样的规范就暂时略过了。然而,这种规范你总是要反复去阅读参照的。关于 Docstring,有两个规范文件:\n", "\n", "> * [PEP 257: Docstring Convensions](https://www.python.org/dev/peps/pep-0257/)\n", "> * [PEP 258: Docutils Design Specification](https://www.python.org/dev/peps/pep-0258/)\n", "\n", "需要**格外注意**的是:\n", "\n", "> Docstring 是**写给人看的**,所以,在复杂代码的 Docstring 中,写 **Why** 要远比写 _What_ 更重要 —— 你先记住这点,以后的体会自然会不断加深。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Sphinx 版本的 Docstring 规范" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sphinx 可以从 `.py` 文件里提取所有 Docstring,而后生成完整的 Documentation。将来若是你写大型的项目,需要生成完善的文档的时候,你就会发现 Sphinx 是个 “救命” 的家伙,省时、省力、省心、省命……\n", "\n", "在这里,没办法一下子讲清楚 Sphinx 的使用,尤其是它还用它自己的一种标记语言,reStructureText,文件尾缀使用 `.rst`……\n", "\n", "但是,可以看一个例子:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on class Vehicle in module __main__:\n", "\n", "class Vehicle(builtins.object)\n", " | Vehicle(arg, *args, **kwargs)\n", " | \n", " | The Vehicle object contains lots of vehicles\n", " | :param arg: The arg is used for ...\n", " | :type arg: str\n", " | :param `*args`: The variable arguments are used for ...\n", " | :param `**kwargs`: The keyword arguments are used for ...\n", " | :ivar arg: This is where we store arg\n", " | :vartype arg: str\n", " | \n", " | Methods defined here:\n", " | \n", " | __init__(self, arg, *args, **kwargs)\n", " | Initialize self. See help(type(self)) for accurate signature.\n", " | \n", " | cars(self, distance, destination)\n", " | We can't travel a certain distance in vehicles without fuels, so here's the fuels\n", " | \n", " | :param distance: The amount of distance traveled\n", " | :type amount: int\n", " | :param bool destinationReached: Should the fuels be refilled to cover required distance?\n", " | :raises: :class:`RuntimeError`: Out of fuel\n", " | \n", " | :returns: A Car mileage\n", " | :rtype: Cars\n", " | \n", " | ----------------------------------------------------------------------\n", " | Data descriptors defined here:\n", " | \n", " | __dict__\n", " | dictionary for instance variables (if defined)\n", " | \n", " | __weakref__\n", " | list of weak references to the object (if defined)\n", "\n" ] } ], "source": [ "class Vehicle(object):\n", " '''\n", " The Vehicle object contains lots of vehicles\n", " :param arg: The arg is used for ...\n", " :type arg: str\n", " :param `*args`: The variable arguments are used for ...\n", " :param `**kwargs`: The keyword arguments are used for ...\n", " :ivar arg: This is where we store arg\n", " :vartype arg: str\n", " '''\n", "\n", "\n", " def __init__(self, arg, *args, **kwargs):\n", " self.arg = arg\n", "\n", " def cars(self, distance, destination):\n", " '''We can't travel a certain distance in vehicles without fuels, so here's the fuels\n", "\n", " :param distance: The amount of distance traveled\n", " :type amount: int\n", " :param bool destinationReached: Should the fuels be refilled to cover required distance?\n", " :raises: :class:`RuntimeError`: Out of fuel\n", "\n", " :returns: A Car mileage\n", " :rtype: Cars\n", " ''' \n", " pass\n", "\n", "help(Vehicle)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "通过插件,Sphinx 也能支持 Google Style Docstring 和 Numpy Style Docstring。\n", "\n", "以下两个链接,放在这里,以便你将来查询:\n", "\n", "> * [sphinx.ext.napoleon – Support for NumPy and Google style docstrings](http://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html)\n", "> * [sphinx.ext.autodoc – Include documentation from docstrings](https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next Page" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.3" }, "toc-autonumbering": true }, "nbformat": 4, "nbformat_minor": 2 }