TypeChecking para uma função que retorna None

Aug 23 2020

Considere a implementação recursiva da função fatorial -

from typing import Optional

def factorial(val: int) -> Optional[int]:
    if val<0:
        return None
    if val==0:
        return 1
    return val*factorial(val-1)


if __name__ == "__main__":
    print(square_root(3))

Estou usando mypypara verificação de tipo estático. Isso me dá o seguinte erro -

type-hints.py:8: error: Unsupported operand types for * ("int" and "None")
type-hints.py:8: note: Right operand is of type "Optional[int]"
Found 1 error in 1 file (checked 1 source file)

Eu tentei usar Optionalde acordo com esta questão do stackoverflow. Mas não parece funcionar. Alguma sugestão?

Perguntas -

  1. Como especificar o tipo de retorno quando a função retorna None?
  2. Parece um pouco surpreendente para mim que mypy foi capaz de imaginar uma situação em que a multiplicação entre inte Nonepode ocorrer. Por exemplo - Se eu remover o argumento intfor val e chamar a função fatorial com um float, isso poderá gerar esse erro.

Respostas

2 MisterMiyagi Aug 23 2020 at 03:01

MyPy está correto ao dizer que a função não está bem digitada. A assinatura da função é (int) -> Optional[int], tornando val*factorial(val-1) possivelmente errônea. Isso Noneocorre apenas para informações val < 0de tipo não estático.

Em vez de retornar Nonepara entrada inválida, gere uma exceção. Isso torna a função estaticamente bem tipada, sem remover o tratamento de erros.

def factorial(val: int) -> int:
    if val<0:
        raise ValueError("factorial() not defined for negative values")
    if val==0:
        return 1
    return val*factorial(val-1)

Se retornar Nonefor necessário por algum motivo, anote explicitamente que a expressão é sólida e não precisa ser verificada.

def factorial(val: int) -> int:
    if val<0:
        return None
    if val==0:
        return 1
    return val*factorial(val-1)  # type: ignore