Reputation: 1875
Consider the recursive implementation of factorial function -
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))
I am using mypy
for static type checking. It throws me the following 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)
I tried using Optional
as per this stackoverflow question. But it doesn't seem to work. Any suggestions?
Questions -
None
?int
and None
might occur. For example - If I remove int
for val argument and call the factorial function with a float, it might throw such error.Upvotes: 3
Views: 988
Reputation: 50076
MyPy is correct that the function is not well-typed. The signature of the function is (int) -> Optional[int]
, making val*factorial(val-1)
possibly erroneous. That None
only occurs for val < 0
is not static type information.
Instead of returning None
for invalid input, raise an exception. This makes the function statically well-typed, without removing the error handling.
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)
If returning None
is required for some reason, explicitly annotate that the expression is sound and does not need checking.
def factorial(val: int) -> int:
if val<0:
return None
if val==0:
return 1
return val*factorial(val-1) # type: ignore
Upvotes: 3