Anotação de tipo de retorno void Python

108

No python 3.x, é comum usar a anotação de tipo de retorno de uma função, como:

def foo() -> str:
    return "bar"

Qual é a anotação correta para o tipo "vazio"?

Estou considerando 3 opções:

  1. def foo() -> None:
    • não lógico IMO, porque Nonenão é um tipo,
  2. def foo() -> type(None):
    • usando a melhor sintaxe que conheço para obter NoneType,
  3. def foo():
    • omitir informações de tipo de retorno explícito.

A opção 2. parece a mais lógica para mim, mas já vi alguns exemplos de 1.

Tregoreg
fonte
11
FWIW, Python não tem funções com voidtipo de retorno. Qualquer função (ou ramificação em uma função) sem um returnretorno explícito None. Presumo que o OP entenda isso, este comentário é principalmente para o benefício dos futuros leitores ...
PM 2Ring de
Bem, essa pergunta não é tão popular quanto "por que minha função retorna Nenhum em Python?" (Eu inventei essa questão), então provavelmente a maioria dos leitores já conhece o comportamento padrão. O dilema 1 vs 2 é resolvido na resposta. Mas e quanto a 3? Para "procedimentos", na verdade, prefiro a opção 3, sem confusão desnecessária (afinal, essa função não retorna nada).
Tomasz Gandor
@TomaszGandor Agree. Quando uma função ou método não contém nenhuma instrução de retorno, é desnecessário especificar seu tipo de retorno.
Jeyekomon

Respostas:

121

Isto é direto do PEP 484 - Documentação de dicas de tipo :

Quando usada em uma dica de tipo, a expressão Noneé considerada equivalente a type(None).

E, como você pode ver, a maioria dos exemplos usa Nonecomo tipo de retorno.

AKS
fonte
22
Para esclarecer, escolha a opção 1 acima.
Adam Nelson
6
E quanto ao tipo NoReturn python.org/dev/peps/pep-0484/#the-noreturn-type ?
asmaier
12
@asmaier de acordo com esta questão que cita PEP 484 - Tipo de dicas NoReturn é usado "... para anotar funções que nunca retornam normalmente. Por exemplo, uma função que incondicionalmente levanta uma exceção ..."
Rodrigo Laguna
38

TLDR: o equivalente idiomático de uma voidanotação de tipo de retorno é -> None.

def foo() -> None:
    ...

Isso corresponde a uma função sem returnou apenas uma returnavaliação None.

def void_func():  # unannotated void function
    pass

print(void())  # None

Omitir o tipo de retorno não significa que não haja valor de retorno. Conforme PEP 484 :

Para uma função marcada, a anotação padrão para argumentos e para o tipo de retorno é Any.

Isso significa que o valor é considerado digitado dinamicamente e oferece suporte estático a qualquer operação . Esse é praticamente o significado oposto de void.


A sugestão de tipo em Python não exige estritamente tipos reais. Por exemplo, as anotações podem usar cordas de nomes de tipo: Union[str, int], Union[str, 'int'], 'Union[str, int]'e diversas variantes são equivalentes.

Da mesma forma, a anotação de tipo Noneé considerada como significando "é de NoneType". Isso pode ser usado não apenas para tipos de retorno, embora você o veja com mais frequência lá:

bar : None

def foo(baz: None) -> None:
    return None

Isso também se aplica a tipos genéricos. Por exemplo, você pode usar Nonein Generator[int, None, None]para indicar que um gerador não recebe ou retorna valores.


Embora o PEP 484 sugira esses Nonemeios type(None), você não deve usar a última forma explicitamente. A especificação de sugestão de tipo não inclui nenhuma forma de type(...). Esta é tecnicamente uma expressão de tempo de execução e seu suporte depende inteiramente do verificador de tipo. O mypyprojeto está considerando a possibilidade de remover o suporte para type(None)e remova-o 484 também.

Ou talvez devêssemos atualizar o PEP 484 para não sugerir que type(None)é válido como um tipo e Noneé a única grafia correta? Deve haver uma - e de preferência apenas uma - maneira óbvia de fazer isso, etc.

--- JukkaL, 18 de maio de 2018

MisterMiyagi
fonte
4
Grande mensagem para explicar por que a 3ª opção não é, na verdade, função nula.
никта