1 為什么要編寫注釋
“Code is more often read than written.”
— Guido Van Rossum
“It doesn’t matter how good your software is, because if the documentation is not good enough, people will not use it.“
— Daniele Procida
如果想做一名職業軟件工程師,代碼注釋是非常重要的,不論是對於團隊還是對於自己。一段自己編寫的代碼(尤其是業務或算法復雜的代碼)如果沒有合理的注釋,很快自己都不知道自己當時寫的是什么,更不用說別人的代碼了,毫無疑問這就是程序員所說的”坑“。因此良好的注釋是不給自己挖坑也不給別人挖坑。
2 python的兩種注釋
python有兩種方式進行注釋:
- docstring 。這種方式的注釋是python提供的一種語言特性,即python代碼本身是“自注釋”的,即便編譯成pyc二進制文件,docstring仍然是存在的。
- 普通注釋 。以“#”開頭的注釋,這種類型的注釋和其他編程語言是一致的,編譯成pyc后就消失了。
例如:
def print_msg(msg):
'''
這里是docstring注釋
Args:
msg (str): the msg to show
'''
# 這里是普通注釋
print("hello" + msg)
這兩種方式的注釋是有區別的:
- docstring注釋是給“用戶”看的(自己也可以是用戶),例如編寫了一個模塊、庫,供別人或自己使用,那么就需要使用docstring編寫注釋,這里的注釋更像是“使用手冊”
- 普通注釋是給“開發者”看的,它們需要通過普通的注釋去了解代碼內部的原理
在大多數編程語言中,當我們要查看一些庫的使用方法的時候,我們只能借助該庫的網上在線手冊、離線手冊、書籍、dash/zeal軟件等,但熟練的python程序員則根本不用這些各種渠道的使用手冊,他們只使用 help
函數即可解決問題,而該函數的作用就是格式化輸出docstrig。
例如,上述的 print_msg 函數,假設它發布為一個Python庫:idiot_print ,用戶只需要導入庫,使用 help(idiot_print.print_msg)
即可查看該函數的手冊:
help(idiot_print.print_msg)
Help on function print_msg in module idiot_print:
print_msg(msg)
這里是docstring注釋
Args:
msg (str): the msg to show
(END)
docstring是一個絕妙的主意,它通過語言的特性“統一了使用手冊”,使得熟練的python程序員一般很少登錄 docs.python.org 查閱手冊資料,他們僅需要 help
就解決問題了。
在下文中將主要介紹docsting類型的注釋,對於普通注釋,僅在這里列舉一下編寫原則:
- 注釋應當離被注釋的對象盡可能的近。
- 不要使用圖表等復雜格式進行注釋。
- 不要事無巨細,要假設閱讀你的代碼的人擁有基本的領域知識。
- 代碼應當“自釋義”,最好的代碼不需要注釋,自己本身就是注釋,尤其對於python這樣的和自然語言比較貼近的語言,提高可讀性本身比編寫注釋更重要。
3 如何編寫docstring注釋
java程序員都知道 javadoc
這個工具,可以根據注釋生成文檔。python本身並不包含這樣的工具,但python有一個非常著名的工具 sphinx, 該工具提供了類似於 javadoc
的功能,程序員可以使用reStructuredText文本標記語言編寫文檔,然后將文檔編譯生成html/pdf/epub等格式。
sphinx
工具生成的手冊大多數程序員都見過,例如python的官方手冊,你可以在網頁右下角看到 sphinx 的技術支持說明。
程序員常用的 readthedoc 也主要使用sphinx來生成文檔。另一個類似的工具是gitbook;經常有程序員會拿 readthedoc
和 gitbook
比較,筆者認為前者更適合用於編寫技術手冊、開發手冊,而后者則更適合用於寫書。如今IT行業的技術手冊,使用 reStructuredText+sphinx+readthedoc 方式幾乎是一種共識。
sphinx
提供了 autodoc 的插件,可以導入一個模塊,根據docstring生成用戶手冊。所以,python的docstring注釋會使用 reStructuredText
作為文本標記語言,生成文檔的時候都是帶有“格式”的,並且不同風格的docstring均會“擴展”一些語法,在最終使用sphinx生成手冊的時候需要一些sphinx插件用於解析擴展的語法,下文的docstring格式示例會看到這一點。
常見的python程序注釋風格有3種:
- google推薦的注釋風格,支持模塊、類、函數、變量注釋,非常詳細,且易於閱讀。
- numpy風格的注釋,支持模塊模塊、類、函數、變量注釋,同樣易於閱讀。
- sphinx風格的注釋,支持函數、類,通過sphinx格式化輸出比較漂亮,但閱讀性弱一些。
筆者這里推薦使用第一種風格的注釋,當然這三種風格的注釋可以混用,只要格式簡潔、易於閱讀、不會產生歧義即可,著名的openstack社區多使用sphinx風格的注釋,但也做了一些自己的修改、增強。
3.1 google風格的docstring注釋
下文中的google風格注釋原文出處 google_style_docstrings
# -*- coding: utf-8 -*-
# 這里是模塊的docstring注釋,在py文件開頭編寫,模塊級別的變量可以在模塊中注釋,也可以在變量
# 所在行后面注釋,注意變量的注釋並不是python語法支持的,僅用於生成文檔
"""Example Google style docstrings.
This module demonstrates documentation as specified by the `Google Python
Style Guide`_. Docstrings may extend over multiple lines. Sections are created
with a section header and a colon followed by a block of indented text.
Example:
Examples can be given using either the ``Example`` or ``Examples``
sections. Sections support any reStructuredText formatting, including
literal blocks::
$ python example_google.py
Section breaks are created by resuming unindented text. Section breaks
are also implicitly created anytime a new section starts.
Attributes:
module_level_variable1 (int): Module level variables may be documented in
either the ``Attributes`` section of the module docstring, or in an
inline docstring immediately following the variable.
Either form is acceptable, but the two should not be mixed. Choose
one convention to document module level variables and be consistent
with it.
Todo:
* For module TODOs
* You have to also use ``sphinx.ext.todo`` extension
.. _Google Python Style Guide:
http://google.github.io/styleguide/pyguide.html
"""
module_level_variable1 = 12345
# 這里是對模塊級的變量進行docstring注釋
module_level_variable2 = 98765
"""int: Module level variable documented inline.
The docstring may span multiple lines. The type may optionally be specified
on the first line, separated by a colon.
"""
# 函數的docstring示例,可以看到這里面使用了reStructuredText語法
def function_with_types_in_docstring(param1, param2):
"""Example function with types documented in the docstring.
`PEP 484`_ type annotations are supported. If attribute, parameter, and
return types are annotated according to `PEP 484`_, they do not need to be
included in the docstring:
Args:
param1 (int): The first parameter.
param2 (str): The second parameter.
Returns:
bool: The return value. True for success, False otherwise.
.. _PEP 484:
https://www.python.org/dev/peps/pep-0484/
"""
def function_with_pep484_type_annotations(param1: int, param2: str) -> bool:
"""Example function with PEP 484 type annotations.
Args:
param1: The first parameter.
param2: The second parameter.
Returns:
The return value. True for success, False otherwise.
"""
def module_level_function(param1, param2=None, *args, **kwargs):
"""This is an example of a module level function.
Function parameters should be documented in the ``Args`` section. The name
of each parameter is required. The type and description of each parameter
is optional, but should be included if not obvious.
If ``*args`` or ``**kwargs`` are accepted,
they should be listed as ``*args`` and ``**kwargs``.
The format for a parameter is::
name (type): description
The description may span multiple lines. Following
lines should be indented. The "(type)" is optional.
Multiple paragraphs are supported in parameter
descriptions.
Args:
param1 (int): The first parameter.
param2 (:obj:`str`, optional): The second parameter. Defaults to None.
Second line of description should be indented.
*args: Variable length argument list.
**kwargs: Arbitrary keyword arguments.
Returns:
bool: True if successful, False otherwise.
The return type is optional and may be specified at the beginning of
the ``Returns`` section followed by a colon.
The ``Returns`` section may span multiple lines and paragraphs.
Following lines should be indented to match the first line.
The ``Returns`` section supports any reStructuredText formatting,
including literal blocks::
{
'param1': param1,
'param2': param2
}
Raises:
AttributeError: The ``Raises`` section is a list of all exceptions
that are relevant to the interface.
ValueError: If `param2` is equal to `param1`.
"""
if param1 == param2:
raise ValueError('param1 may not be equal to param2')
return True
# google風格的docstring注釋也支持生成器
def example_generator(n):
"""Generators have a ``Yields`` section instead of a ``Returns`` section.
Args:
n (int): The upper limit of the range to generate, from 0 to `n` - 1.
Yields:
int: The next number in the range of 0 to `n` - 1.
Examples:
Examples should be written in doctest format, and should illustrate how
to use the function.
>>> print([i for i in example_generator(4)])
[0, 1, 2, 3]
"""
for i in range(n):
yield i
# exception docstring注釋
class ExampleError(Exception):
"""Exceptions are documented in the same way as classes.
The __init__ method may be documented in either the class level
docstring, or as a docstring on the __init__ method itself.
Either form is acceptable, but the two should not be mixed. Choose one
convention to document the __init__ method and be consistent with it.
Note:
Do not include the `self` parameter in the ``Args`` section.
Args:
msg (str): Human readable string describing the exception.
code (:obj:`int`, optional): Error code.
Attributes:
msg (str): Human readable string describing the exception.
code (int): Exception error code.
"""
def __init__(self, msg, code):
self.msg = msg
self.code = code
# 類的docstring注釋
class ExampleClass(object):
"""The summary line for a class docstring should fit on one line.
If the class has public attributes, they may be documented here
in an ``Attributes`` section and follow the same formatting as a
function's ``Args`` section. Alternatively, attributes may be documented
inline with the attribute's declaration (see __init__ method below).
Properties created with the ``@property`` decorator should be documented
in the property's getter method.
Attributes:
attr1 (str): Description of `attr1`.
attr2 (:obj:`int`, optional): Description of `attr2`.
"""
def __init__(self, param1, param2, param3):
"""Example of docstring on the __init__ method.
The __init__ method may be documented in either the class level
docstring, or as a docstring on the __init__ method itself.
Either form is acceptable, but the two should not be mixed. Choose one
convention to document the __init__ method and be consistent with it.
Note:
Do not include the `self` parameter in the ``Args`` section.
Args:
param1 (str): Description of `param1`.
param2 (:obj:`int`, optional): Description of `param2`. Multiple
lines are supported.
param3 (list(str)): Description of `param3`.
"""
self.attr1 = param1
self.attr2 = param2
self.attr3 = param3 #: Doc comment *inline* with attribute
#: list(str): Doc comment *before* attribute, with type specified
self.attr4 = ['attr4']
self.attr5 = None
"""str: Docstring *after* attribute, with type specified."""
@property
def readonly_property(self):
"""str: Properties should be documented in their getter method."""
return 'readonly_property'
@property
def readwrite_property(self):
"""list(str): Properties with both a getter and setter
should only be documented in their getter method.
If the setter method contains notable behavior, it should be
mentioned here.
"""
return ['readwrite_property']
@readwrite_property.setter
def readwrite_property(self, value):
value
def example_method(self, param1, param2):
"""Class methods are similar to regular functions.
Note:
Do not include the `self` parameter in the ``Args`` section.
Args:
param1: The first parameter.
param2: The second parameter.
Returns:
True if successful, False otherwise.
"""
return True
def __special__(self):
"""By default special members with docstrings are not included.
Special members are any methods or attributes that start with and
end with a double underscore. Any special member with a docstring
will be included in the output, if
``napoleon_include_special_with_doc`` is set to True.
This behavior can be enabled by changing the following setting in
Sphinx's conf.py::
napoleon_include_special_with_doc = True
"""
pass
def __special_without_docstring__(self):
pass
def _private(self):
"""By default private members are not included.
Private members are any methods or attributes that start with an
underscore and are *not* special. By default they are not included
in the output.
This behavior can be changed such that private members *are* included
by changing the following setting in Sphinx's conf.py::
napoleon_include_private_with_doc = True
"""
pass
def _private_without_docstring(self):
pass
在使用sphinx生成手冊的時候需要在conf.py中添加sphinx.ext.napoleon
插件。
{: .notice--info}
3.2 nmupy風格的docstring注釋
下文中的numpy風格注釋原文出處 numpy_style_docstrings
# -*- coding: utf-8 -*-
"""Example NumPy style docstrings.
This module demonstrates documentation as specified by the `NumPy
Documentation HOWTO`_. Docstrings may extend over multiple lines. Sections
are created with a section header followed by an underline of equal length.
Example
-------
Examples can be given using either the ``Example`` or ``Examples``
sections. Sections support any reStructuredText formatting, including
literal blocks::
$ python example_numpy.py
Section breaks are created with two blank lines. Section breaks are also
implicitly created anytime a new section starts. Section bodies *may* be
indented:
Notes
-----
This is an example of an indented section. It's like any other section,
but the body is indented to help it stand out from surrounding text.
If a section is indented, then a section break is created by
resuming unindented text.
Attributes
----------
module_level_variable1 : int
Module level variables may be documented in either the ``Attributes``
section of the module docstring, or in an inline docstring immediately
following the variable.
Either form is acceptable, but the two should not be mixed. Choose
one convention to document module level variables and be consistent
with it.
.. _NumPy Documentation HOWTO:
https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt
"""
module_level_variable1 = 12345
module_level_variable2 = 98765
"""int: Module level variable documented inline.
The docstring may span multiple lines. The type may optionally be specified
on the first line, separated by a colon.
"""
def function_with_types_in_docstring(param1, param2):
"""Example function with types documented in the docstring.
`PEP484`_ type annotations are supported. If attribute, parameter, and
return types are annotated according to `PEP484`_, they do not need to be
included in the docstring:
.. _PEP484: https://www.python.org/dev/peps/pep-0484/
Parameters
----------
param1 : int
The first parameter.
param2 : str
The second parameter.
Returns
-------
bool
True if successful, False otherwise.
"""
def function_with_pep484_type_annotations(param1: int, param2: str) -> bool:
"""Example function with PEP 484 type annotations.
The return type must be duplicated in the docstring to comply
with the NumPy docstring style.
Parameters
----------
param1
The first parameter.
param2
The second parameter.
Returns
-------
bool
True if successful, False otherwise.
"""
def module_level_function(param1, param2=None, *args, **kwargs):
"""This is an example of a module level function.
Function parameters should be documented in the ``Parameters`` section.
The name of each parameter is required. The type and description of each
parameter is optional, but should be included if not obvious.
If ``*args`` or ``**kwargs`` are accepted,
they should be listed as ``*args`` and ``**kwargs``.
The format for a parameter is::
name : type
description
The description may span multiple lines. Following lines
should be indented to match the first line of the description.
The ": type" is optional.
Multiple paragraphs are supported in parameter
descriptions.
Parameters
----------
param1 : int
The first parameter.
param2 : :obj:`str`, optional
The second parameter.
*args
Variable length argument list.
**kwargs
Arbitrary keyword arguments.
Returns
-------
bool
True if successful, False otherwise.
The return type is not optional. The ``Returns`` section may span
multiple lines and paragraphs. Following lines should be indented to
match the first line of the description.
The ``Returns`` section supports any reStructuredText formatting,
including literal blocks::
{
'param1': param1,
'param2': param2
}
Raises
------
AttributeError
The ``Raises`` section is a list of all exceptions
that are relevant to the interface.
ValueError
If `param2` is equal to `param1`.
"""
if param1 == param2:
raise ValueError('param1 may not be equal to param2')
return True
def example_generator(n):
"""Generators have a ``Yields`` section instead of a ``Returns`` section.
Parameters
----------
n : int
The upper limit of the range to generate, from 0 to `n` - 1.
Yields
------
int
The next number in the range of 0 to `n` - 1.
Examples
--------
Examples should be written in doctest format, and should illustrate how
to use the function.
>>> print([i for i in example_generator(4)])
[0, 1, 2, 3]
"""
for i in range(n):
yield i
class ExampleError(Exception):
"""Exceptions are documented in the same way as classes.
The __init__ method may be documented in either the class level
docstring, or as a docstring on the __init__ method itself.
Either form is acceptable, but the two should not be mixed. Choose one
convention to document the __init__ method and be consistent with it.
Note
----
Do not include the `self` parameter in the ``Parameters`` section.
Parameters
----------
msg : str
Human readable string describing the exception.
code : :obj:`int`, optional
Numeric error code.
Attributes
----------
msg : str
Human readable string describing the exception.
code : int
Numeric error code.
"""
def __init__(self, msg, code):
self.msg = msg
self.code = code
class ExampleClass(object):
"""The summary line for a class docstring should fit on one line.
If the class has public attributes, they may be documented here
in an ``Attributes`` section and follow the same formatting as a
function's ``Args`` section. Alternatively, attributes may be documented
inline with the attribute's declaration (see __init__ method below).
Properties created with the ``@property`` decorator should be documented
in the property's getter method.
Attributes
----------
attr1 : str
Description of `attr1`.
attr2 : :obj:`int`, optional
Description of `attr2`.
"""
def __init__(self, param1, param2, param3):
"""Example of docstring on the __init__ method.
The __init__ method may be documented in either the class level
docstring, or as a docstring on the __init__ method itself.
Either form is acceptable, but the two should not be mixed. Choose one
convention to document the __init__ method and be consistent with it.
Note
----
Do not include the `self` parameter in the ``Parameters`` section.
Parameters
----------
param1 : str
Description of `param1`.
param2 : list(str)
Description of `param2`. Multiple
lines are supported.
param3 : :obj:`int`, optional
Description of `param3`.
"""
self.attr1 = param1
self.attr2 = param2
self.attr3 = param3 #: Doc comment *inline* with attribute
#: list(str): Doc comment *before* attribute, with type specified
self.attr4 = ["attr4"]
self.attr5 = None
"""str: Docstring *after* attribute, with type specified."""
@property
def readonly_property(self):
"""str: Properties should be documented in their getter method."""
return "readonly_property"
@property
def readwrite_property(self):
"""list(str): Properties with both a getter and setter
should only be documented in their getter method.
If the setter method contains notable behavior, it should be
mentioned here.
"""
return ["readwrite_property"]
@readwrite_property.setter
def readwrite_property(self, value):
value
def example_method(self, param1, param2):
"""Class methods are similar to regular functions.
Note
----
Do not include the `self` parameter in the ``Parameters`` section.
Parameters
----------
param1
The first parameter.
param2
The second parameter.
Returns
-------
bool
True if successful, False otherwise.
"""
return True
def __special__(self):
"""By default special members with docstrings are not included.
Special members are any methods or attributes that start with and
end with a double underscore. Any special member with a docstring
will be included in the output, if
``napoleon_include_special_with_doc`` is set to True.
This behavior can be enabled by changing the following setting in
Sphinx's conf.py::
napoleon_include_special_with_doc = True
"""
pass
def __special_without_docstring__(self):
pass
def _private(self):
"""By default private members are not included.
Private members are any methods or attributes that start with an
underscore and are *not* special. By default they are not included
in the output.
This behavior can be changed such that private members *are* included
by changing the following setting in Sphinx's conf.py::
napoleon_include_private_with_doc = True
"""
pass
def _private_without_docstring(self):
pass
在使用sphinx生成手冊的時候需要在conf.py中添加sphinx.ext.napoleon
插件。
{: .notice--info}
3.3 sphinx風格的docstring注釋
示例如下
# -*- coding: utf-8 -*-
"""Example Sphinx style docstrings.
This module demonstrates documentation as specified by the
`Sphinx Python Style Guide`_. Docstrings may extend over multiple lines.
Sections are created with a section header and a colon followed by a
block of indented text.
Example:
Examples can be given using either the ``Example`` or ``Examples``
sections. Sections support any reStructuredText formatting, including
literal blocks::
$ python example_google.py
Section breaks are created by resuming unindented text. Section breaks
are also implicitly created anytime a new section starts.
Todo:
* For module TODOs
* You have to also use ``sphinx.ext.todo`` extension
.. _Sphinx Python Style Guide:
https://pythonhosted.org/an_example_pypi_project/sphinx.html#full-code-example
"""
# sphinx 風格的docstring注釋不支持變量注釋,不過可以使用google風格的,實際上numpy風格
# 的變量注釋和google風格是一樣的
module_level_variable1 = 12345
module_level_variable2 = 98765
"""int: Module level variable documented inline.
The docstring may span multiple lines. The type may optionally be specified
on the first line, separated by a colon.
"""
# 函數的注釋,注意這里type和param是分開的,會損失可讀性
def function_with_types_in_docstring(param1, param2):
"""Example function with types documented in the docstring.
`PEP 484`_ type annotations are supported. If attribute, parameter, and
return types are annotated according to `PEP 484`_, they do not need to be
included in the docstring:
:param param1: The first parameter.
:type param1: int
:param param2: The second parameter.
:type param2: str
:returns: The return value. True for success, False otherwise.
:rtype: bool
.. _PEP 484:
https://www.python.org/dev/peps/pep-0484/
"""
def function_with_pep484_type_annotations(param1: int, param2: str) -> bool:
"""Example function with PEP 484 type annotations.
:param param1: The first parameter.
:param param2: The second parameter.
:returns: The return value. True for success, False otherwise.
"""
# 類方式的docstring注釋
class ExampleClass(object):
"""The summary line for a class docstring should fit on one line.
"""
def __init__(self, param1, param2, param3):
"""Example of docstring on the __init__ method.
The __init__ method may be documented in either the class level
docstring, or as a docstring on the __init__ method itself.
Either form is acceptable, but the two should not be mixed. Choose one
convention to document the __init__ method and be consistent with it.
Note:
Do not include the `self` parameter in the ``Args`` section.
:param param1: The first parameter.
:type param1: str
:param param2: The second parameter.
:type param2: int
:param param3: The third parameter.
"""
self.attr1 = param1
self.attr2 = param2
self.attr3 = param3 #: Doc comment *inline* with attribute
#: list(str): Doc comment *before* attribute, with type specified
self.attr4 = ['attr4']
self.attr5 = None
"""str: Docstring *after* attribute, with type specified."""
def example_method(self, param1, param2):
"""Class methods are similar to regular functions.
Note:
Do not include the `self` parameter in the ``Args`` section.
:param param1: The first parameter.
:type param1: str
:param param2: The second parameter.
:type param2: int
:returns: The return value. True for success, False otherwise.
:rtype: bool
"""
return True
def __special__(self):
"""By default special members with docstrings are not included.
Special members are any methods or attributes that start with and
end with a double underscore. Any special member with a docstring
will be included in the output, if
``napoleon_include_special_with_doc`` is set to True.
This behavior can be enabled by changing the following setting in
Sphinx's conf.py::
napoleon_include_special_with_doc = True
"""
pass
def __special_without_docstring__(self):
pass
def _private(self):
"""By default private members are not included.
Private members are any methods or attributes that start with an
underscore and are *not* special. By default they are not included
in the output.
This behavior can be changed such that private members *are* included
by changing the following setting in Sphinx's conf.py::
napoleon_include_private_with_doc = True
"""
pass
def _private_without_docstring(self):
pass
4 使用sphinx生成手冊
sphinx的使用在本文中不再贅述,可參考sphinx官方手冊,下文僅介紹使用sphinx的幾個插件根據docstring自動生成python項目的使用手冊。
正常情況下,一個python項目,建議在項目根目錄下新建一個目錄 docs ,在這個目錄中存放手冊文檔(openstack社區每個項目都有一個這樣的目錄),在這個目錄中運行
sphinx-quickstart
該命令初始化sphinx項目,該命令會以交互式方式詢問一些問題,大部分情況直接選默認,生成的配置會寫入到 conf.py 文件,后期可以根據需要修改這個文件。
在這里我將創建一個 python_comment 的python項目(項目內容就是python各種風格的docstring示例代碼),可點擊 這里 下載該項目。
使用這個命令后,我們的項目目錄結構為
python_comment
├── docs
│ ├── Makefile
│ ├── _build
│ ├── _static
│ ├── _templates
│ ├── conf.py
│ ├── google_style.rst
│ ├── index.rst
│ ├── make.bat
│ ├── modules.rst
│ ├── numpy_style.rst
│ └── sphinx_style.rst
├── google_style.py
├── numpy_style.py
└── sphinx_style.py
下面需要修改 conf.py 配置文件,用於支持手冊生成。
首先要做的修改是:讓sphinx能夠找到代碼在哪里。sphinx會通過 sys.path 來找到代碼的位置,所以如果是自己編寫的項目,則需要將項目路徑加入到 sys.path ,例如在python_comment項目中,需要添加如下代碼到 conf.py 開頭部分:
import os
import sys
sys.path.insert(0, os.path.abspath('..'))
其次,正如上文所述,為了讓sphinx生成漂亮的手冊,我們需要增加一些插件支持,仍然是修改 conf.py ,將 extensions 列表修改為:
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.napoleon',
'sphinx.ext.todo'
]
現在我們剩下最后一步,編寫rst文檔來告訴sphinx應該生成哪些模塊、類、函數的文檔。而這一步通常不需要自己手動編寫,使用 sphinx-apidoc 命令即可生成所有模塊的rst文檔,然后自己根據需要進行裁剪即可。例如在python_comment項目中,在python_comment目錄下執行如下shell命令:
sphinx-apidoc -f -o docs .
其中, -f 參數強制重寫同名文件,-o 參數指定輸出的目錄,最后的"."則指定對於 python_comment 項目目錄下的所有python文件生成rst文檔
此時會在docs目錄下看到新增加了4個文件:
├── modules.rst
├── google_style.rst
├── numpy_style.rst
├── sphinx_style.rst
modules.rst 相當於一個入口,引用了其他幾個文件
然后,我們需要更改 index.rst 文件,讓它引用 modules.rst,例如加入如下代碼:
.. toctree::
:maxdepth: 2
modules
此時,執行 make html
即可生成文檔,例如使用 classic 模板生成文檔如下圖
5 參考
- https://realpython.com/documenting-python-code/
- http://www.sphinx-doc.org/en/1.6/ext/example_google.html?highlight=Python%20Docstrings
- http://www.sphinx-doc.org/en/1.6/ext/example_numpy.html#example-numpy
- https://pythonhosted.org/an_example_pypi_project/sphinx.html#full-code-example
- https://gisellezeno.com/tutorials/sphinx-for-python-documentation.html
- https://medium.com/@eikonomega/getting-started-with-sphinx-autodoc-part-1-2cebbbca5365
- http://www.sphinx-doc.org/en/1.4/man/sphinx-apidoc.html