Qual é a maneira correta de documentar um parâmetro ** kwargs?

99

Estou usando o sphinx e o plug-in autodoc para gerar documentação de API para meus módulos Python. Embora eu possa ver como documentar bem parâmetros específicos, não consigo encontrar um exemplo de como documentar um **kwargsparâmetro.

Alguém tem um bom exemplo de uma maneira clara de documentar isso?

jkp
fonte
Isso depende inteiramente de qual método docstring você usa. (reStructuredText, Sphinx, Google)
Stevoisiak
2
Isso não deveria ter sido fechado. É uma pergunta válida. É específico (como documentar ** kwargs usando sphinx) Como os comentários de documentos não são totalmente padronizados em python, isso resultará em opiniões (ou vários métodos), desde que apóiem ​​a questão especificamente (sphinx).
JerodG

Respostas:

5

Eu acho que subprocessa documentação do -module é um bom exemplo. Forneça uma lista exaustiva de todos os parâmetros para uma classe principal / pai . Em seguida, basta consultar essa lista para todas as outras ocorrências de **kwargs.

SilentGhost
fonte
97
Eu sou o único para quem essa resposta não faz sentido? Não consegui encontrar o exemplo específico em questão.
Acumenus
2
O exemplo é provável subprocess.call(*popenargs, **kwargs). Está documentado subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False)onde tudo o que *vem depois de são as chaves reconhecidas em **kwargs(ou pelo menos aquelas usadas com freqüência)
nos
2
A continuação mais significativa disso é agora subprocess.Popene não tenho mais certeza se é um exemplo particularmente bom.
Donal Fellows
A menos que eu esteja enganado, isso não está mais documentado no Python 3.7 .
Mateen Ulhaq
10
Downvoting por não incluir um exemplo real na resposta.
naught101
51

Depois de encontrar essa questão, resolvi o seguinte, que é o Sphinx válido e funciona muito bem:

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

    """

O r"""..."""é necessário para tornar esta uma docstring "bruta" e, assim, manter a \*intacta (para Sphinx entender como um literal *e não como o início de "ênfase").

A formatação escolhida (lista com marcadores com tipo entre parênteses e descrição separada por m-traços) é simplesmente para corresponder à formatação automatizada fornecida pelo Sphinx.

Depois de fazer o esforço de fazer a seção "Argumentos de palavra-chave" parecer a seção "Parâmetros" padrão, parece que será mais fácil rolar sua própria seção de parâmetros desde o início (de acordo com algumas das outras respostas) , mas como prova de conceito, essa é uma maneira de conseguir um visual legal para suplementar **kwargsse você já estiver usando o Sphinx.

quorniano
fonte
26

Documentos do Google Style analisados ​​por Sphinx

Aviso: não testado.

A partir deste recorte do exemplo de docstring da esfinge , o *argse não **kwargssão expandidos :

def module_level_function(param1, param2=None, *args, **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.

Eu sugeriria a seguinte solução para compactação:

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

Observe como, Optionalnão é necessário para **keyargumentos.

Caso contrário , você pode tentar listar explicitamente os * argumentos sob Other Parameterse **kwargssob Keyword Args(consulte as seções analisadas ):

    """
    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 
        ...
Oleg
fonte
9

Há um exemplo doctstring para Sphinx em sua documentação. Especificamente, eles mostram o seguinte:

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

Embora você tenha perguntado sobre explicitamente, eu também apontaria para o Guia de estilo do Google Python . Seu exemplo de docstring parece implicar que eles não chamam kwargs especificamente. (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 ABB tem uma pergunta sobre a resposta aceita de fazer referência à documentação de gerenciamento de subprocesso. Se você importar um módulo, poderá ver rapidamente as docstrings do módulo por meio de inspect.getsource.

Um exemplo do interpretador python usando a recomendação do Silent Ghost:

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

É claro que você também pode visualizar a documentação do módulo por meio da função de ajuda. Por exemplo, ajuda (subprocesso)

Pessoalmente, não sou um fã do subprocesso docstring para kwargs como exemplo, mas como o exemplo do Google, ele não lista kwargs separadamente, conforme mostrado no exemplo de documentação do 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()

Estou incluindo esta resposta à pergunta da ABB porque vale a pena observar que você pode revisar a fonte ou a documentação de qualquer módulo dessa forma para obter insights e inspiração para comentar seu código.

substrato binário
fonte
2
Correção: isso não faz parte da documentação do Sphinx, mas de um 'projeto pypi de exemplo' independente, que se descreve explicitamente como um tutorial não oficial.
menino,
other_silly_variablenão é um argumento kwargs, mas completamente normal.
bugmenot123
4

Se alguém estiver procurando por alguma sintaxe válida .. Aqui está um exemplo de docstring. Foi assim que fiz, espero que seja útil para você, mas não posso afirmar que seja compatível com nada em particular.

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
m01
fonte
3
E quanto aos argumentos de palavras-chave individuais?
maasha
4

Isso depende do estilo de documentação que você usa, mas se você estiver usando o estilo numpydoc , é recomendável documentar **kwargsusando Other Parameters.

Por exemplo, seguindo o exemplo da 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}``.
    """

Observe especialmente que é recomendado fornecer os padrões de kwargs, uma vez que eles não são óbvios pela assinatura da função.

Jonas Adler
fonte
1
Não tenho certeza se sua sugestão é tirada de documentos antigos ou de experiência pessoal, mas a documentação atual de "Outros parâmetros" (para a qual você tem um link) afirma que deve ser "usada para descrever parâmetros usados ​​com pouca frequência" e "apenas ser usada se uma função tiver um grande número de parâmetros de palavras-chave, para evitar confundir a seção Parâmetros ".
Ninjakannon 01 de
1

Se você está procurando como fazer isso no estilo numpydoc , você pode simplesmente mencionar **kwargsna seção Parâmetros sem especificar o tipo - conforme demonstrado no exemplo numpydoc do guia de extensão napolean e docstring do pandas documentation sprint 2018.

Aqui está um exemplo que encontrei no guia do desenvolvedor LSST que explica muito bem qual deve ser a descrição do **kwargsparâmetro:

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

Como alternativa, com base no que @Jonas Adler sugeriu, acho melhor colocar o **kwargse sua descrição na Other Parametersseção - até mesmo este exemplo do guia de documentação matplotlib sugere o mesmo.

Jaladh Singhal
fonte