How to make mypy complain about assigning an Any t

2019-08-15 01:04发布

问题:

mypy --strict dutifully complains about the following code:

from typing import Any, Dict

def main() -> None:
    my_str: str = 'hello'
    my_int: int = my_str

if __name__ == "__main__":
    main()

by outputting:

error: Incompatible types in assignment (expression has type "str", variable has type "int")

However the following code is accepted without any error:

from typing import Any, Dict

def main() -> None:
    my_str: Any = 'hello'
    my_int: int = my_str

if __name__ == "__main__":
    main()

Is there an option for mypy to make it also reject the second example?

I expect it to do so, because it also rejects the following:

from typing import Any, Dict, Union

def main() -> None:
    my_str: Union[int, str] = 'hello'
    my_int: int = my_str

if __name__ == "__main__":
    main()

with:

error: Incompatible types in assignment (expression has type "Union[int, str]", variable has type "int")

And in my understanding an Any is just the Union of all possible types.

回答1:

And in my understanding an Any is just the Union of all possible types.

That's not correct. Any is an escape hatch, an annotation for variables that you want the type checker to ignore. It certainly is not a union.

From the mypy documentation on Any:

A value with the Any type is dynamically typed. Mypy doesn’t know anything about the possible runtime types of such value. Any operations are permitted on the value, and the operations are only checked at runtime. You can use Any as an “escape hatch” when you can’t use a more precise type for some reason.

(Bold emphasise mine)

It explicitly covers your case:

Any is compatible with every other type, and vice versa. You can freely assign a value of type Any to a variable with a more precise type:

a: Any = None
s: str = ''
a = 2     # OK (assign "int" to "Any")
s = a     # OK (assign "Any" to "str")

Declared (and inferred) types are ignored (or erased) at runtime. They are basically treated as comments, and thus the above code does not generate a runtime error, even though s gets an int value when the program is run, while the declared type of s is actually str!

So the correct approach is to not use Any if you want the type checker to keep tracking how the value is used. Use a Union[], as you did in your third example, or re-think your data structures to allow for better type hinting. For example, rather than use a dictionary with a union value type, consider using a named tuple or dataclass with explicit fields and a specific type for each field.



回答2:

For those that read about this later, the actual solution is to use the "disallow any" family of command line flags, as describes in this answer.