【问题标题】:What is the correct way to document a **kwargs parameter?记录 **kwargs 参数的正确方法是什么?
【发布时间】:2010-11-11 08:25:29
【问题描述】:

我正在使用 Sphinxautodoc extension 为我的 Python 模块生成 API 文档。虽然我可以看到如何很好地记录特定参数,但我找不到如何记录 **kwargs 参数的示例。

有没有人有一个很好的例子来清楚地记录这些?

【问题讨论】:

  • 这完全取决于您使用的文档字符串方法。 (reStructuredText、Sphinx、谷歌)
  • 这不应该被关闭。这是一个有效的问题。它是具体的(如何使用 sphinx 记录 **kwargs)由于 doc cmets 在 python 中并未完全标准化,只要它们专门支持问题(sphinx),就会产生意见(或多种方法)。
  • 看在上帝的份上,不要使用 **kwargs。它缺乏清晰度,没有文档记录并且失去 IDE 支持。

标签: python python-sphinx autodoc


【解决方案1】:

在找到这个问题后,我确定了以下问题,这是有效的 Sphinx 并且运行良好:

def some_function(first, second="two", **kwargs):
    r"""Fetches and returns this thing

    :param first:
        The first parameter
    :type first: ``int``
    :param second:
        The second parameter
    :type second: ``str``
    :param \**kwargs:
        See below

    :Keyword Arguments:
        * *extra* (``list``) --
          Extra stuff
        * *supplement* (``dict``) --
          Additional content

    """

r"""...""" 需要使其成为“原始”文档字符串,从而保持 \* 完整(以便 Sphinx 将其作为文字 * 而不是“强调”的开头)。

选择的格式(带括号的类型和 m 破折号分隔的描述的项目符号列表)只是为了匹配 Sphinx 提供的自动格式。

一旦您努力使“关键字参数”部分看起来像默认的“参数”部分,似乎从一开始就滚动您自己的参数部分可能更容易(根据一些其他答案),但作为概念证明,如果您已经在使用 Sphinx,这是获得补充 **kwargs 的漂亮外观的一种方法。

【讨论】:

  • 看在上帝的份上,请不要使用**kwargs。它缺乏清晰度、没有文档记录、失去 IDE 支持并且令人困惑。
【解决方案2】:

Sphinx 解析的 Google 样式文档字符串

免责声明:未经测试。

sphinx docstring example 的这个切口中,*args**kwargs 保持未展开

def module_level_function(param1, *args, param2=None, **kwargs):
    """
    ...

    Args:
        param1 (int): The first parameter.
        param2 (Optional[str]): The second parameter. Defaults to None.
            Second line of description should be indented.
        *args: Variable length argument list.
        **kwargs: Arbitrary keyword arguments.

我会建议以下紧凑性解决方案:

    """
    Args:
        param1 (int): The first parameter.
        param2 (Optional[str]): The second parameter. Defaults to None.
            Second line of description should be indented.
        *param3 (int): description
        *param4 (str): 
        ...
        **key1 (int): description 
        **key2 (int): description 
        ...

注意,Optional 不需要 **key 参数。

否则,您可以尝试在Keyword Args 下显式列出Other Parameters**kwargs 下的*args(参见docstring sections):

    """
    Args:
        param1 (int): The first parameter.
        param2 (Optional[str]): The second parameter. Defaults to None.
            Second line of description should be indented.
    
    Other Parameters:
        param3 (int): description
        param4 (str): 
        ...

    Keyword Args:
        key1 (int): description 
        key2 (int): description 
        ...

【讨论】:

  • 这段代码看起来语法错误。 *args 作为位置参数不能放在 param2=None 之后。
  • @Lohengrin 感谢您的发现,修改。,
【解决方案3】:

在他们的文档中有一个doctstring example 代表 Sphinx。具体来说,它们显示以下内容:

def public_fn_with_googley_docstring(name, state=None):
"""This function does something.

Args:
   name (str):  The name to use.

Kwargs:
   state (bool): Current state to be in.

Returns:
   int.  The return code::

      0 -- Success!
      1 -- No good.
      2 -- Try again.

Raises:
   AttributeError, KeyError

A really great idea.  A way you might use me is

>>> print public_fn_with_googley_docstring(name='foo', state=None)
0

BTW, this always returns 0.  **NEVER** use with :class:`MyPublicClass`.

"""
return 0

虽然您明确询问了,但我也会指出Google Python Style Guide。他们的文档字符串示例似乎暗示他们没有专门调用 kwargs。 (other_silly_variable=None)

def fetch_bigtable_rows(big_table, keys, other_silly_variable=None):
"""Fetches rows from a Bigtable.

Retrieves rows pertaining to the given keys from the Table instance
represented by big_table.  Silly things may happen if
other_silly_variable is not None.

Args:
    big_table: An open Bigtable Table instance.
    keys: A sequence of strings representing the key of each table row
        to fetch.
    other_silly_variable: Another optional variable, that has a much
        longer name than the other args, and which does nothing.

Returns:
    A dict mapping keys to the corresponding table row data
    fetched. Each row is represented as a tuple of strings. For
    example:

    {'Serak': ('Rigel VII', 'Preparer'),
     'Zim': ('Irk', 'Invader'),
     'Lrrr': ('Omicron Persei 8', 'Emperor')}

    If a key from the keys argument is missing from the dictionary,
    then that row was not found in the table.

Raises:
    IOError: An error occurred accessing the bigtable.Table object.
"""
pass

A-B-B 对引用子流程管理文档的公认答案有疑问。如果您导入一个模块,您可以通过 inspect.getsource 快速查看模块文档字符串。

使用 Silent Ghost 推荐的 Python 解释器示例:

>>> import subprocess
>>> import inspect
>>> import print inspect.getsource(subprocess)

当然您也可以通过帮助功能查看模块文档。例如帮助(子进程)

我个人并不喜欢以 kwargs 为例的子流程文档字符串,但与 Google 示例一样,它没有单独列出 kwargs,如 Sphinx 文档示例中所示。

def call(*popenargs, **kwargs):
"""Run command with arguments.  Wait for command to complete, then
return the returncode attribute.

The arguments are the same as for the Popen constructor.  Example:

retcode = call(["ls", "-l"])
"""
return Popen(*popenargs, **kwargs).wait()

我将这个答案包含在 A-B-B 的问题中,因为值得注意的是,您可以通过这种方式查看任何模块的源代码或文档,以获得评论代码的见解和灵感。

【讨论】:

  • 更正:这不是 Sphinx 文档的一部分,而是一个独立的“示例 pypi 项目”,它明确将自己描述为非权威教程。
  • other_silly_variable 不是 kwargs 的论点,而是完全正常的论点。
【解决方案4】:

如果您正在寻找如何以 numpydoc 样式执行此操作,您可以简单地在参数部分中提及 **kwargs 而无需指定类型 - 如 sphinx 扩展名中的 numpydoc example 所示和来自 pandas 文档 sprint 2018 的 docstring guide

这是我从LSST developer guide 找到的一个示例,它很好地解释了**kwargs 参数的描述

def demoFunction(namedArg, *args, flag=False, **kwargs):
    """Demonstrate documentation for additional keyword and
    positional arguments.

    Parameters
    ----------
    namedArg : `str`
        A named argument that is documented like always.
    *args : `str`
        Additional names.

        Notice how the type is singular since the user is expected to pass individual
        `str` arguments, even though the function itself sees ``args`` as an iterable
        of `str` objects).
    flag : `bool`
        A regular keyword argument.
    **kwargs
        Additional keyword arguments passed to `otherApi`.

        Usually kwargs are used to pass parameters to other functions and
        methods. If that is the case, be sure to mention (and link) the
        API or APIs that receive the keyword arguments.

        If kwargs are being used to generate a `dict`, use the description to
        document the use of the keys and the types of the values.
    """

或者,基于@Jonas Adler 的建议,我发现最好**kwargs 及其描述放在Other Parameters 部分 - 甚至matplotlib 文档指南中的this example 也建议相同.

【讨论】:

    【解决方案5】:

    如果其他人正在寻找一些有效的语法。这是一个示例文档字符串。我就是这样做的,希望它对你有用,但我不能声称它符合任何特定的要求。

    def bar(x=True, y=False):
        """
        Just some silly bar function.
    
        :Parameters:
          - `x` (`bool`) - dummy description for x
          - `y` (`string`) - dummy description for y
        :return: (`string`) concatenation of x and y.
        """
        return str(x) + y
    
    def foo (a, b, **kwargs):
        """
        Do foo on a, b and some other objects.
    
        :Parameters:
          - `a` (`int`) - A number.
          - `b` (`int`, `string`) - Another number, or maybe a string.
          - `\**kwargs` - remaining keyword arguments are passed to `bar`
    
        :return: Success
        :rtype: `bool`
        """
        return len(str(a) + str(b) + bar(**kwargs)) > 20
    

    【讨论】:

    • 那么各个关键字参数呢?
    • 我经常使用这个约定,提到它们被传递给什么函数,但将定义留给拥有它们的函数。那么当它们被重构时,多个文档字符串就不需要更新了。
    【解决方案6】:

    这取决于您使用的文档样式,但如果您使用numpydoc 样式,建议使用Other Parameters 记录**kwargs

    例如,以quornian为例:

    def some_function(first, second="two", **kwargs):
        """Fetches and returns this thing
    
        Parameters
        ----------
        first : `int`
            The first parameter
        second : `str`, optional
            The second parameter
    
        Other Parameters
        ----------------
        extra : `list`, optional
            Extra stuff. Default ``[]``.
        suplement : `dict`, optional
            Additional content. Default ``{'key' : 42}``.
        """
    

    请特别注意,建议给出 kwargs 的默认值,因为这些在函数签名中并不明显。

    【讨论】:

    • 我不确定您的建议是来自较早的文档还是个人经验,但当前的“其他参数”文档(您链接到的)指出它应该“用于描述不经常使用的参数”并且是“仅在函数具有大量关键字参数时使用,以防止参数部分混乱”。
    【解决方案7】:

    我无法找到文档的实际链接,但这有效(使用 Sphinx 3.4.3):

    class Foo:
        """A Foo implementation
    
        :param str foo: Foo
        :param int bar: Bar
        :keyword str key1: kwarg 1
        :keyword str key2: kwarg 2
        :keyword int key3: kwarg 3
        """
    
        def __init__(self, foo, bar, **kwargs):
            pass
    

    【讨论】:

    【解决方案8】:

    我认为subprocess-module's docs 是一个很好的例子。给出top/parent class 的所有参数的详尽列表。然后只需参考该列表以了解所有其他出现的 **kwargs

    【讨论】:

    • 我是唯一一个对这个答案毫无意义的人吗?我找不到有问题的具体示例。
    • 例子很可能是subprocess.call(*popenargs, **kwargs)。它被记录为subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False),其中* 之后的所有内容都是**kwargs 中公认的键(或者至少是经常使用的键)
    • 现在最有意义的延续是subprocess.Popen,我不确定这是否是一个特别好的例子。
    • 除非我记错了,否则Python 3.7 中不再记录。
    • 因未在答案中包含实际示例而投反对票。
    猜你喜欢
    • 2013-12-13
    • 1970-01-01
    • 1970-01-01
    • 2011-06-27
    • 1970-01-01
    • 2014-08-04
    • 2016-06-28
    • 2014-04-13
    • 2011-08-10
    相关资源
    最近更新 更多