如何使用Sphinx的autodoc来记录类的__init__(self)方法?

126

Sphinx默认不会为__init__(self)生成文档。我尝试过以下方法:

.. automodule:: mymodule
    :members:

..autoclass:: MyClass
    :members:
在conf.py中,只设置以下内容会将__init__(self)的docstring追加到类docstring中。(Sphinx autodoc documentation似乎认为这是预期行为,但未提及我要解决的问题):
autoclass_content = 'both'

1
不,至少截至今天,文档并没有写成这样:"both" Both the class’ and the __init__ method’s docstring are concatenated and inserted. -> 因此,如果你有类的docstring,它不应该只是__init__(self),而且还应该包括类的docstring。你能提供一个测试用例吗?因为如果是这样,感觉像是一个bug,对吧? - László Papp
6个回答

128

这里有三种替代方案:

  1. To ensure that __init__() is always documented, you can use autodoc-skip-member in conf.py. Like this:

    def skip(app, what, name, obj, would_skip, options):
        if name == "__init__":
            return False
        return would_skip
    
    def setup(app):
        app.connect("autodoc-skip-member", skip)
    

    This explicitly defines __init__ not to be skipped (which it is by default). This configuration is specified once, and it does not require any additional markup for every class in the .rst source.

  2. The special-members option was added in Sphinx 1.1. It makes "special" members (those with names like __special__) be documented by autodoc.

    Since Sphinx 1.2, this option takes arguments which makes it more useful than it was previously.

  3. Use automethod:

    .. autoclass:: MyClass     
       :members: 
    
       .. automethod:: __init__
    

    This has to be added for every class (cannot be used with automodule, as pointed out in a comment to the first revision of this answer).


8
对于 automodule 来说,这并没有帮助,因为它必须被添加到每个类中。 - Roger Binns
3
第一个替代方案可行。在我的情况下,它比第二和第三个替代方案更好,因为它不需要编辑.rst文件。 - jcarballo
10
在 Sphinx 1.2.1 版本中,使用 automodule 可以正常使用 special-members。使用 :special-members: __init__ 只记录 __init__ 方法。 - Florian Brucker
1
在Sphinx 5.3.0中,这些替代方案都对我无效。 - G M

95

你很接近了。你可以在你的conf.py文件中使用autoclass_content选项:

autoclass_content = 'both'

1
@MichaelMrozek:我也在想这个问题……你明白这个答案为什么有如此高的赞同率吗?起初,它看起来像是一个应该被清除的答案。 - László Papp
2
我尝试设置 autoclass_content = 'both' 选项,可以记录 init 方法,但它会使自动摘要出现两次。 - Stretch
2
这是最好的方法,它与autosummary完美配合,结果比“special-methods”要好得多。前者将构造函数文档添加到类的开头,而后者将一个单独的__init__方法添加到文档中。 - Terseus

15

尽管这篇文章比较旧,但对于现在查找此信息的人来说,版本1.8中还引入了另一种解决方案。根据文档,您可以在conf.py文件中的autodoc_default_options键中添加special-members关键字。

例如:

autodoc_default_options = {
    'members': True,
    'member-order': 'bysource',
    'special-members': '__init__',
    'undoc-members': True,
    'exclude-members': '__weakref__'
}

7
在过去的几年中,我为几个不相关的 Python 项目编写了几个 autodoc-skip-member 回调函数的变体,因为我希望像 __init__()__enter__()__exit__() 这样的方法显示在我的 API 文档中(毕竟,这些“特殊方法”是 API 的一部分,最好的地方就是在特殊方法的文档字符串中记录它们)。
最近,我将最佳实现之一并入了我的一个 Python 项目中(这里是文档)。这个实现 基本上就是这样的:
import types

def setup(app):
    """Enable Sphinx customizations."""
    enable_special_methods(app)


def enable_special_methods(app):
    """
    Enable documenting "special methods" using the autodoc_ extension.

    :param app: The Sphinx application object.

    This function connects the :func:`special_methods_callback()` function to
    ``autodoc-skip-member`` events.

    .. _autodoc: http://www.sphinx-doc.org/en/stable/ext/autodoc.html
    """
    app.connect('autodoc-skip-member', special_methods_callback)


def special_methods_callback(app, what, name, obj, skip, options):
    """
    Enable documenting "special methods" using the autodoc_ extension.

    Refer to :func:`enable_special_methods()` to enable the use of this
    function (you probably don't want to call
    :func:`special_methods_callback()` directly).

    This function implements a callback for ``autodoc-skip-member`` events to
    include documented "special methods" (method names with two leading and two
    trailing underscores) in your documentation. The result is similar to the
    use of the ``special-members`` flag with one big difference: Special
    methods are included but other types of members are ignored. This means
    that attributes like ``__weakref__`` will always be ignored (this was my
    main annoyance with the ``special-members`` flag).

    The parameters expected by this function are those defined for Sphinx event
    callback functions (i.e. I'm not going to document them here :-).
    """
    if getattr(obj, '__doc__', None) and isinstance(obj, (types.FunctionType, types.MethodType)):
        return False
    else:
        return skip

是的,有比逻辑更多的文档 :-). 定义一个像这样的autodoc-skip-member回调函数的优点是,与使用special-members选项相比(对我来说),special-members选项还启用了诸如__weakref__之类的属性的文档(在所有新式类上都可用,据我所知),而我认为这是噪音,没有任何用处。回调方法避免了这种情况(因为它仅适用于函数/方法并忽略其他属性)。

我该如何使用它?似乎必须将方法命名为 setup(app) 才能被 Sphinx 执行。 - oarfish
我不是很理解,但如果你想自己分析,可以看看xolox的实现。我相信他构建了一个sphinx扩展,将回调连接到autodoc-skip-member事件上。当sphinx尝试确定是否应该包含/跳过某些内容时,该事件会触发,然后运行他的代码。如果他的代码检测到用户明确定义的__special__成员(通常是继承的),则告诉Sphinx将其包含在内。这样,您就可以记录自己编写的特殊成员。 - Andrew
感谢您的澄清,安德鲁。是的,你说得对,需要一个设置函数。我已经将其添加到示例中,以避免进一步的混淆。 - xolox
@JoelB:我在帖子中的示例代码是写成假定你的 __init__ 方法有一个非空的文档字符串。是这样吗? - xolox

1
只要这个提交被批准:https://github.com/sphinx-doc/sphinx/pull/9154,在下一个sphinx版本(>4.1.2)中将可以:
..autoclass:: MyClass1
    :members:
    :class-doc-from: class


..autoclass:: MyClass2
    :members:
    :class-doc-from: init

1
正确的语法是去掉引号,变成这样: :class-doc-from: class - Harshil Mehta

0

这是一种变体,仅在具有参数时包括__init__

import inspect

def skip_init_without_args(app, what, name, obj, would_skip, options):
    if name == '__init__':
        func = getattr(obj, '__init__')
        spec = inspect.getfullargspec(func)
        return not spec.args and not spec.varargs and not spec.varkw and not spec.kwonlyargs
    return would_skip

def setup(app):
    app.connect("autodoc-skip-member", skip_init_without_args)

对我没有起作用。 - G M

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接