Sphinx 中的 Google 风格 Python Docstring 完整指南:以 Napoleon 与 example_google.py 为实战范例

原创2026-09-28 23:59:58564 阅读
文章标签:文档开发工具

Sphinx 中的 Google 风格 Python Docstring 完整指南:以 Napoleon 与 example_google.py 为实战范例

导读

本文围绕 Sphinx 仓库自带的 Google 风格 Docstring 示例页 及其配套源码 example_google.py 展开,系统讲解如何用 sphinx.ext.napoleon 扩展解析 Google 风格 docstring 并生成结构化 API 文档。读完本文,你将掌握 Google 风格 docstring 的模块级、函数级、类级写法规范、与 PEP 484/526 类型注解的配合方式、Napoleon 全部配置项的语义,以及该解析机制在源码层面的工作原理,可直接套用于自己的项目。

这份示例文档是什么

doc/usage/extensions/example_google.rst 是一份被标记为 :orphan: 的独立页面(不会自动进入文档目录树),它的作用是完整展示"用 Google Python 风格指南撰写 docstring 的模块长什么样"。页面主体只有三个动作:

  • 通过 :ref:example_numpy`` 在 seealso 中指向 NumPy 风格示例页,方便读者对照两种风格;
  • 仅在 HTML 构建器下(.. only:: builder_html)提供 :download: 下载链接,指向 example_google.py 本身;
  • 通过 literalinclude 指令把 example_google.py 的完整源码原样嵌入页面,并以 :language: python 声明语法高亮。

也就是说,这份"文档"的真正技术内容全部沉淀在示例源码里。该示例与 napoleon.rst 中的 Napoleon 扩展文档互为表里:前者提供符合规范的 docstring 全文,后者解释这些 docstring 会被如何解析和渲染。

启用 Napoleon 的前置条件

Napoleon 是 Sphinx 的官方扩展(自 Sphinx 1.3 起提供),作用是解析 Google 与 NumPy 两种风格的 docstring。启用方式是在 conf.py 中加入:

# conf.py
extensions = ['sphinx.ext.napoleon']

随后可用 sphinx-apidoc 从项目目录生成 API 文档骨架:

$ sphinx-apidoc -f -o docs/source projectdir

Napoleon 是一个预处理器:它在 Sphinx 解析 docstring 之前,先把 Google/NumPy 风格内容转换成 reStructuredText,再交给 docutils 处理。转换发生在构建的中间步骤,不会修改源文件里的任何 docstring。因此凡是 sphinx.ext.autodoc 能找到的 docstring——模块、类、属性、方法、函数、变量——都会经过 Napoleon 的解释。

模块级 Docstring:如何描述整个模块

示例模块的 docstring 首先给出摘要与扩展描述,然后说明该文档遵循 Google Python 风格指南,并提示"docstring 可跨多行,节(section)由『节标题 + 冒号 + 缩进文本块』构成":

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

这段文字同时示范了两条关键规则:

  1. Example/Examples 节:用于给出示例,节体内可以使用任何 reStructuredText 格式,包括 :: 引入的字面量块;
  2. 节的分隔规则:Google 风格依靠"缩进"划分节——恢复非缩进文本即表示上一个节结束;任何新节开始也隐式终结当前节。

随后模块 docstring 用 Attributes 节说明模块级变量,并用 Todo 节声明待办事项:

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

示例特意指出 Todo 节要真正渲染出来,还必须在 conf.py 中同时启用 sphinx.ext.todo 扩展——这是"节支持"与"扩展渲染"互相配合的典型体现。

模块级变量的两种文档化方式

示例通过两个真实变量演示了两种等价写法,并强调"两种方式都可用,但同一项目不要混用":

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.
"""
  • module_level_variable1:在模块 docstring 的 Attributes 节里统一说明;
  • module_level_variable2:紧随变量声明之后用独立 docstring 内联说明,类型写在第一行并用冒号分隔。

函数 Docstring:Args、Returns 与 Raises

类型写在 docstring 里的写法

当函数没有使用 PEP 484 注解时,类型信息需要直接写进 docstring:

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

参数条目遵循 name (type): description 格式,返回条目则是 type: description(类型可选)。

使用 PEP 484 注解的写法

若参数与返回值都已按 PEP 484 注解,docstring 中就无需重复类型:

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

这样既避免信息冗余,又让类型检查器和 IDE 能直接利用注解做静态分析。

完整参数格式:默认值、*args、**kwargs 与多行描述

module_level_function 展示了最完整的 Google 参数写法:

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:
        msg = 'param1 may not be equal to param2'
        raise ValueError(msg)
    return True

需要继承的关键规范:

  • 参数名必须出现;类型与描述可选,但"不明显时应尽量给出";
  • 可变长参数以 *args、**kwargs 原样列出;
  • 描述可跨多行,续行必须缩进;支持多个段落;
  • 可选参数习惯标注 optional(如 (:obj:str, optional)),并说明默认值;
  • Returns 节可跨多行、多段落,支持任意 reStructuredText 格式(包括字面量块);
  • Raises 节逐一列出接口相关的异常及触发条件,函数体内也确实实现了 ValueError 的抛出逻辑,代码与文档互相印证。

生成器:用 Yields 代替 Returns

生成器函数的输出应写在 Yields 节;Examples 节则应写成 doctest 格式,可被 sphinx.ext.doctest 直接验证:

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]

    """
    yield from range(n)

异常类与类的 Docstring

异常类的写法

异常类按类的相同方式文档化:__init__ 既可写进类级 docstring,也可写在 __init__ 方法自身,但二者不可混用。示例选择在类级 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

注意两点惯例:self 永远不要写进 Args;异常类的 Args 与 Attributes 常成对出现,分别描述构造入参与最终属性。

普通类的写法

class ExampleClass:
    """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`.

    """

规范要点:摘要行应在一行内收束;公开属性要么集中写进类级 Attributes,要么内联在声明处,同样不可混用;@property 装饰的属性一律在其 getter 方法中文档化。

init 与实例属性的内联文档

__init__ 自身的 docstring 与类级 docstring 二选一。示例展示了三种内联属性文档写法同时存在以作对照:

def __init__(self, param1, param2, param3):
    """Example of docstring on the __init__ method.
    ...
    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."""
  • #: 注释与属性同行(inline),或置于属性声明之前(before,可含类型);
  • 独立的字符串 docstring 放在属性赋值之后(after,可含类型);
  • 类型同样遵循"首行、冒号分隔"的规则。

property 的文档位置

@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

可读写属性的文档只写进 getter;若 setter 有值得注意的行为,也应在此提及。这样 Sphinx 渲染属性时能得到完整说明。

方法 Docstring 与成员收录控制

普通方法与函数规则一致,同样强调 self 不写入 Args:

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

特殊成员与私有成员的收录开关

示例专门定义了几个对照成员,说明默认收录行为与对应的 conf.py 开关:

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
  • 特殊成员(__name__ 形式):默认不带 docstring 的不输出;带 docstring 的,需设置 napoleon_include_special_with_doc = True 才纳入输出;
  • 私有成员(单下划线开头、非特殊):默认一律不输出;需要时设置 napoleon_include_private_with_doc = True。

PEP 526 类属性注解

ExamplePEP526Class 演示了变量注解与类 docstring 配合:当 napoleon_attr_annotations 为 True 时,类体中用 PEP 526 语法声明的类型会被拾取,因此 Attributes 节里可以省略类型:

class ExamplePEP526Class:
    """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. If ``napoleon_attr_annotations``
    is True, types can be specified in the class body using ``PEP 526``
    annotations.

    Attributes:
        attr1: Description of `attr1`.
        attr2: Description of `attr2`.

    """

    attr1: str
    attr2: int

即:属性在 docstring 中未写类型、但类体内有注解时,注解类型会被采用。

Napoleon 支持的全部 Docstring 节

除上述示例用到的节之外,Napoleon 完整支持的节标题(见 napoleon.rst)如下:

节标题 说明
Args / Arguments Parameters 的别名
Attention / Caution / Danger / Error 渲染为对应 admonition
Attributes 属性说明
Example / Examples 示例(渲染方式受 napoleon_use_admonition_for_examples 控制)
Hint / Important / Note / Tip / Warning / Warnings 提示类 admonition(Warnings 是 Warning 的别名)
Keyword Args / Keyword Arguments 关键字参数
Methods 方法列表
Notes 说明(渲染方式受 napoleon_use_admonition_for_notes 控制)
Other Parameters 次要参数
Parameters 参数
Return / Returns 返回值(Return 是别名)
Raise / Raises 异常(Raise 是别名)
References 参考资料(渲染方式受 napoleon_use_admonition_for_references 控制)
See Also 参见
Todo 待办(需配合 sphinx.ext.todo)
Warn / Warns 告警
Yield / Yields 生成器产出(Yield 是别名)

这些节名在 sphinx/ext/napoleon/docstring.py 的 _sections 字典中与各自的解析函数一一对应(如 args/arguments 映射到 _parse_parameters_section、yields 映射到 _parse_yields_section、各 admonition 节映射到 _parse_admonition)。

Google 风格与 NumPy 风格的区别

Napoleon 同时支持两种风格,核心差异在于分隔方式:

  • Google 风格用缩进划分节(Args: 冒号 + 缩进块);
  • NumPy 风格用下划线划分节(Parameters 标题下加等长下划线)。

同一函数的两种写法对比(完整对照见 example_numpy.py):

# Google 风格
def func(arg1, arg2):
    """Summary line.

    Args:
        arg1 (int): Description of arg1
        arg2 (str): Description of arg2

    Returns:
        bool: Description of return value
    """
    return True
# NumPy 风格
def func(arg1, arg2):
    """Summary line.

    Parameters
    ----------
    arg1 : int
        Description of arg1
    arg2 : str
        Description of arg2

    Returns
    -------
    bool
        Description of return value
    """
    return True

经验取舍:Google 风格更省纵向空间、短小 docstring 易读;NumPy 风格更省横向空间、长而深入的 docstring 更易读。两者主要是审美差异,但项目内应统一选择一种,不要混用。

Napoleon 配置项全解

Napoleon 的全部配置项及默认值如下(可在 conf.py 中覆写,前提是已启用 sphinx.ext.napoleon):

# conf.py
extensions = ['sphinx.ext.napoleon']

napoleon_google_docstring = True                 # 解析 Google 风格
napoleon_numpy_docstring = True                  # 解析 NumPy 风格
napoleon_include_init_with_doc = False           # 是否将 __init__ docstring 单独列出
napoleon_include_private_with_doc = False        # 是否收录带 docstring 的私有成员
napoleon_include_special_with_doc = True         # 是否收录带 docstring 的特殊成员
napoleon_use_admonition_for_examples = False     # Example/Examples 用 admonition 还是 rubric
napoleon_use_admonition_for_notes = False        # Notes 用 admonition 还是 rubric
napoleon_use_admonition_for_references = False   # References 用 admonition 还是 rubric
napoleon_use_ivar = False                        # 实例变量用 :ivar: 还是 .. attribute::
napoleon_use_param = True                        # 参数用 :param: 还是单个 :parameters:
napoleon_use_rtype = True                        # 返回类型用 :rtype: 还是内联
napoleon_preprocess_types = False                # 是否将 docstring 内类型转为引用
napoleon_type_aliases = None                     # 类型名到引用/别名的映射
napoleon_attr_annotations = True                 # 是否使用 PEP 526 类属性注解

各项语义与转换示例(摘自 napoleon.rst):

  • napoleon_include_init_with_doc = True:__init__ 的 docstring 作为独立条目列出;False 则沿用 Sphinx 默认行为(并入类文档)。注意:没有 docstring 的 __init__ 即使置 True 也不会收录。
  • napoleon_use_admonition_for_examples/notes/references:为 True 时相应节渲染为 .. admonition:: 指令,为 False 时渲染为 .. rubric::。具体哪个更美观取决于 HTML 主题。单数 Note 节始终转换为 .. note:: 指令,不受该开关影响。
  • napoleon_use_ivar = True:实例变量 Attributes 节转换为 :ivar attr1: 与 :vartype attr1: 角色;False 时转换为 .. attribute:: attr1 指令并在其下给出 :type:。
  • napoleon_use_param = True:每个参数生成独立的 :param:/:type: 行;False 时所有参数合并为单个 :parameters: 角色、以列表形式呈现。
  • napoleon_use_keyword = True:与 use_param 类似,但作用于关键字参数(Keyword Args 节),生成独立的 :keyword: 角色,渲染时作为独立的"Keyword Arguments"小节展示。
  • napoleon_use_rtype = True:返回类型用 :rtype: 单独输出;False 时类型内联进 :returns: 描述(如 *bool* -- True if successful)。
  • napoleon_preprocess_types = True(自 3.2.1 起,3.5 起对 Google 风格同样生效):把 docstring 中的类型定义转换为引用。
  • napoleon_type_aliases(自 3.2 起,仅当 napoleon_use_param = True 时生效):类型名到其他名称或引用的映射:
napoleon_type_aliases = {
    "CustomType": "mypackage.CustomType",
    "dict-like": ":term:`dict-like <mapping>`",
}

例如 Parameters 节中的 arg1 : CustomType 会被转换为 :type arg1: mypackage.CustomType,arg2 : dict-like 会被转换为 :type arg2: :term:dict-like ``。

  • napoleon_attr_annotations = True(自 3.4 起):类体中的 PEP 526 注解作为属性的类型来源(对应前述 ExamplePEP526Class)。
  • napoleon_custom_sections(自 1.8 起,3.5 扩展):定义自定义节。字符串条目表示"通用节";二元组 (别名, 原节名) 为已有节创建别名;(节名, "params_style" | "returns_style") 则让自定义节按参数节或返回节样式渲染。

源码层面的工作原理

从源码看(sphinx/ext/napoleon/docstring.py),Google 风格的解析由 GoogleDocstring 类完成,其类 docstring 里直接给出了转换对照:

>>> from sphinx.ext.napoleon import Config
>>> config = Config(napoleon_use_param=True, napoleon_use_rtype=True)
>>> docstring = '''One line summary.
...
... Extended description.
...
... Args:
...   arg1(int): Description of `arg1`
...   arg2(str): Description of `arg2`
... Returns:
...   str: Description of return value.
... '''
>>> print(GoogleDocstring(docstring, config))
One line summary.
<BLANKLINE>
Extended description.
<BLANKLINE>
:param arg1: Description of `arg1`
:type arg1: int
:param arg2: Description of `arg2`
:type arg2: str
<BLANKLINE>
:returns: Description of return value.
:rtype: str
<BLANKLINE>

可以推断其内部流程:GoogleDocstring.__init__ 接收 docstring 文本与配置,按行切分为队列后逐行扫描;每遇到一个已注册的节标题(大小写不敏感地查 _sections 字典),就调用对应的 _parse_* 方法,把节内容改写成 reStructuredText 字段(:param:、:type:、:returns:、:rtype:、admonition 指令等)。_sections 字典把 args、arguments、parameters 统一指向 _parse_parameters_section,把 yields 指向 _parse_yields_section,把 attention、warning 等指向 _parse_admonition——这正好解释了上一节"别名"与"admonition 节"为何成立。napoleon_custom_sections 则通过 _load_custom_sections 在运行期向该字典追加条目。

Napoleon 配置的默认值登记在 sphinx/ext/napoleon/init.py 的 Config 类中,并通过 add_config_value 注册到 Sphinx 配置系统('env' 域),因此这些选项可以在构建过程中按环境生效,也能被其它扩展读取。整个转换以预处理器形式挂在 autodoc 的 docstring 获取环节之前,不改动磁盘上的源文件。

如何在自己项目里复现这套写法

  1. 在 conf.py 中启用 Napoleon(见上文),并按需覆写配置项;
  2. 用 sphinx-apidoc -f -o docs/source projectdir 生成 API 文档;
  3. 直接以 example_google.py 为模板:模块级 Attributes/Todo 节、函数 Args/Returns/Raises 节、生成器 Yields 节、doctest 格式 Examples 节、类与 __init__ 的文档分工、#: 内联属性注释、getter 中写 property 文档;
  4. 运行 python example_google.py 可自行验证模块可导入、函数行为与 docstring 描述一致(示例中 module_level_function 在 param1 == param2 时确实抛出 ValueError);
  5. 与 example_numpy.py 对照后选定一种风格,全项目保持一致。

按上述流程操作后,autodoc 会把这些 docstring 渲染成带参数签名、类型链接、异常说明与示例的规范 API 页面,同时你仍可在 docstring 中使用任意 reStructuredText 标记(交叉引用、字面量块等),实现"可读源码 + 高质量文档"两全。

登录后查看全文
sphinx