TypeChecking para una función que devuelve Ninguno

Aug 23 2020

Considere la implementación recursiva de la función factorial:

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))

Estoy usando mypypara la verificación de tipos estáticos. Me arroja el siguiente error:

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)

Intenté usar Optionalsegún esta pregunta de stackoverflow. Pero no parece funcionar. ¿Alguna sugerencia?

Preguntas -

  1. ¿Cómo especificar el tipo de retorno cuando la función regresa None?
  2. Me parece un poco sorprendente que mypy haya podido imaginar una situación en la que podría ocurrir la multiplicación entre inty . NonePor ejemplo, si elimino intel argumento val y llamo a la función factorial con un flotante, podría arrojar dicho error.

Respuestas

2 MisterMiyagi Aug 23 2020 at 03:01

MyPy tiene razón en que la función no está bien escrita. La firma de la función es (int) -> Optional[int], por lo que val*factorial(val-1) posiblemente sea errónea. Eso Nonesolo ocurre para información de val < 0tipo no estático.

En lugar de regresar Nonepor una entrada no válida, genere una excepción. Esto hace que la función esté estáticamente bien tipada, sin eliminar el manejo de errores.

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)

Si se requiere regresar Nonepor alguna razón, anote explícitamente que la expresión es sólida y no necesita verificación.

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