Why doesn’t mypy infer the type of a non-type-hinted parameter from the default value, not giving error?

mypy infers the type of a non-type-hinted variable from the value, giving error as shown below:

v = 100     # `v` is `int`.

v = 200     # No error
v = 3.14    # Error
v = 'Hello' # Error

But mypy doesn’t infer the type of a non-type-hinted parameter from the default value, not giving error as shown below:

def func(x=100):
    x = 200     # No error
    x = 3.14    # No error
    x = 'Hello' # No error

func()

Now, why doesn’t mypy infer the type of a non-type-hinted parameter from the default value, not giving error?

From your initial assignment (100), v variable is of type int. When you modify its value to 200, this is still of type int. However, once you change it to 3.14, it is of type float. Then for “Hello”, which is of type str.

For the function, I think that it has to do with the variables having local scope (not global like the first example) and the fact that you did not type hint either the parameter types or the return type of the function.

If functions or methods are not type hinted at all (e.g. no return type too), they are ignored by type checkers by default, and when called have a signature of (*args: Any, **kwargs: Any) -> Any, or in this case (x: Any = ...) -> Any.
See this mypy playground example for more.

from typing import reveal_type

def a(x=10000):
    return x*x

def b(x: int = 10000) -> int:
    return x*x


reveal_type(a)
reveal_type(b)
main.py:10: note: Revealed type is "def (x: Any =) -> Any"
main.py:11: note: Revealed type is "def (x: builtins.int =) -> builtins.int"
Success: no issues found in 1 source file

Mypy’s being conservative. The correct thing to do is to provide a type signature for the function.

The function could be called later on with any argument, and while x is not None is inferred after the if statement, we could probably have an argument about what should be inferred about the function signature from the following alone:

def func(x=None):
    if x is None:
        #do default
        return
    # use x not None
1 Like