41. Documentação de código#

O Python Enhancement Proposal 257 (PEP 257) trata das convenções para uso de docstrings em Python.

Docstring é uma string literal usada para documentar um módulo, função, classe ou método. Ela pode ser acessada pelo atributo especial __doc__.

# modelo
def fun():
    """This is function fun."""
    pass

# acesso
fun.__doc__
'This is function fun.'

41.1. Tipos de docstrings#

Uma docstring deve ser sempre confinada por um par de aspas triplas, podendo ser (definição própria):

  • Simples: Não contém caracter especial. Exemplo: """ao."""

  • Literal: Precedida por r. Contém pelo menos um caracter “barra invertida” (backslash), isto é, \. Exemplo: r"""a\o."""

  • Unicode: Precedida por u. Contém pelo menos um caracter unicode. Exemplo: u"""áò""".

A docstring utilizada em fun() acima é simples. Abaixo, vemos exemplos equivalentes para os outros dois tipos.

def fun_1():
    """This is fun_1 with a \n."""
    pass

fun_1.__doc__    
'This is fun_1 with a \n.'
def fun_2():
    r"""This is fun_2 with a \n."""
    pass

fun_2.__doc__    
'This is fun_2 with a \\n.'

No exemplo abaixo, seria necessário usar u à frente da docstring caso trabalhássemos fora do encoding UTF-8.

def fun_3():
    u"""fun_3: Zażółć gęślą jaźń. Em português e polonês..."""
    pass

fun_3.__doc__  
'fun_3: Zażółć gęślą jaźń. Em português e polonês...'

41.2. Modos de docstring#

Docstrings podem ser escritas em modo de linha única ou de múltiplas linhas

No exemplo abaixo, a docstring é de linha única.

def s(a:int, b:int):
    """Adiciona a e b."""
    return a + b

[s(i,j) for i,j in zip(range(4),range(1,5))]
[1, 3, 5, 7]

Agora, a docstring é de de linha múltipla (mas fora do padrão).

def sp(a:int, b:int):
    """
    Adiciona e
    multiplica a e b.
    """
    return (a + b, a*b)

[sp(i,j) for i,j in zip(range(4),range(1,5))]
[(1, 0), (3, 2), (5, 6), (7, 12)]

41.3. Estrutura de docstrings de múltiplas linhas#

Docstrings de linha única são úteis para descrever ações simples. Quando precisamos documentar algo mais complexo, usamos docstrings com algumas estruturas (ou estilos). Existem diversas estruturas de documetnação, mas entre as mais populares, estão:

41.3.1. Estrutura Google#

"""
Esta é uma docstring em estilo Google.

Args:
    param1: Primeiro parâmetro.
    param2: Segundo parâmetro.

Returns:
    Descrição do retorno.

Raises:
    KeyError: Exceção lançada.
"""

41.3.2. Estrutura numpydoc#

"""
Esta é uma docstring em estilo numpydoc exaustiva.

Parameters
----------
first : array_like
    primeiro parâmetro
second :
    segundo parâmetro
third : {'value', 'other'}, optional
    terceiro parâmetro, by default 'value'

Returns
-------
string
    a value in a string

Raises
------
KeyError
    when a key error
OtherError
    when an other error
"""

41.3.3. Estrutura reST#

"""
Esta é uma docstring em estilo reST.

:param param1: Primeiro parâmetro.
:param param2: Segundo parâmetro.
:returns: Descrição do retorno.
:raises keyError: Exceção lançada.
"""

41.3.4. Sphinx#

Sphinx é um gerador de documentação em Python baseado no estilo reST de grande utilidade para desenvolvedores de código. Ele possui diversas características, tais como múltiplos formatos de saída, extensões, temas etc.

A seguir, temos um exemplo de função apropriadamente documentada para o Sphinx.

def hamming(s1: str,s2: str):
    """Calcula a distância de Hamming entre strings.
    
    :param s1: primeira string .
    :param s2: segunda string.
    :returns: distância entre s1 e s2 pela métrica de Hamming.
    :raises RuntimeError: strings devem ter o mesmo comprimento.
    """
    
    # Strings devem possuir mesmo comprimento para serem comparadas.
    # Caso contrário, lança exceção
    if len(s1) != len(s2):
        raise RuntimeError
    
    # Associa False(True) para caracteres diferentes(iguais) e soma a quantidade de True. 
    return sum(c1 != c2 for c1, c2 in zip(s1,s2))
  • Teste da função de Hamming

s31, s32 = 'pão', 'são'
s33, s34 = 'teu', 'tua'
s35, s36 = 'ali', 'seu'

hamming(s31,s32), hamming(s33,s34), hamming(s35,s36)
(1, 2, 3)
  • Impressão da documentação

print(hamming.__doc__)
Calcula a distância de Hamming entre strings.
    
    :param s1: primeira string .
    :param s2: segunda string.
    :returns: distância entre s1 e s2 pela métrica de Hamming.
    :raises RuntimeError: strings devem ter o mesmo comprimento.
    
  • Documentação reescrita no estilo numpydoc

def hamming_numpydoc(s1: str,s2: str):
    """Calcula a distância de Hamming entre strings.
 
    Parameters
    ----------
    first : str
        primeira string.
    second: str
        segunda string.

    Returns
    -------
    int
        distância de Hamming.

    Raises
    ------
    RuntimeError
        Se strings tiverem comprimento distinto
    """
    
    # Strings devem possuir mesmo comprimento para serem comparadas.
    # Caso contrário, lança exceção
    if len(s1) != len(s2):
        raise RuntimeError
    
    # Associa False(True) para caracteres diferentes(iguais) e soma a quantidade de True. 
    return sum(c1 != c2 for c1, c2 in zip(s1,s2))
  • Impressão da nova documentação

print(hamming_numpydoc.__doc__)
Calcula a distância de Hamming entre strings.
 
    Parameters
    ----------
    first : str
        primeira string.
    second: str
        segunda string.

    Returns
    -------
    int
        distância de Hamming.

    Raises
    ------
    RuntimeError
        Se strings tiverem comprimento distinto