The following code is rejected by mypy
as expected:
def foo(value: int) -> None:
print(value, type(value))
foo(None)
output:
error: Argument 1 to "foo" has incompatible type "None"; expected "int"
But after introducing a default parameter of None
, there is no error anymore:
def foo(value: int=None) -> None:
print(value, type(value))
foo(None)
I would expect mypy
to only allow None
(as argument and as the default) if we change value
from int
to Optional[int]
, but it seems like this is not needed. Why?
When you make a keyword argument accept None
, mypy will implicitly make that argument be of type Optional[Blah]
if it isn't already. You can see this by adding the reveal_type(...)
function to your code and running mypy
:
def foo(value: int = None) -> None:
print(value, type(value))
reveal_type(foo)
foo(None)
The output would be:
test.py:4: error: Revealed type is 'def (value: Union[builtins.int, None] =)'
(Be sure to delete reveal_type
before actually running your code though, since the function doesn't actually exist at runtime -- it's just special-cased by mypy to help with debugging.)
This behavior exists mostly because it helps makes the signatures of functions less noisy. After all, if value
, at some point, is allowed to be None, clearly it must accept both ints and None. In that case, why not just infer the type to be Optional[int]
(which is equivalent to Union[int, None]
, btw) so the user doesn't need to repeat the same info twice?
Of course, not everybody likes this behavior: some people prefer being more explicit. In that case, run mypy with the --no-implicit-optional
flag. That will produce the following output:
test.py:1: error: Incompatible default for argument "value" (default has type "None", argument has type "int")
test.py:4: error: Revealed type is 'def (value: builtins.int =)'
test.py:5: error: Argument 1 to "foo" has incompatible type "None"; expected "int"
You'd need to change your function signature though, of course.
If you'd like to raise the strictness of mypy in various other ways, try passing the --strict
flag. That will automatically enable --no-implicit-optional
and several other strictness flags. For more details, run mypy --help
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With