Reputation: 10872
In the following example, why does the type of the variable foo
change when it's value is set to an integer but the same doesn't occur for the type of bar["foo"]
?
import typing as tp
foo: tp.Union[float, int]
D = tp.TypedDict("D", {"foo": tp.Union[float, int]})
foo = 123.45
bar = D(foo=123.45)
reveal_type(foo) # main.py:9: note: Revealed type is 'builtins.float'
reveal_type(bar["foo"]) # main.py:10: note: Revealed type is 'builtins.float'
foo = int(foo)
bar["foo"] = int(bar["foo"])
reveal_type(foo) # main.py:15: note: Revealed type is 'builtins.int'
reveal_type(bar["foo"]) # main.py:16: note: Revealed type is 'builtins.float'
Upvotes: 1
Views: 276
Reputation: 32233
This is due to some mypy
features:
Union
.Any assignment after the initial declaration will narrow the type down
x: Union[int, float]
x = 1.1
reveal_type(x) # Revealed type is 'builtins.float'
But mypy
does not narrow down types in an assignment:
x: Union[int, float] = 1.1
reveal_type(x) # Revealed type is 'Union[builtins.int, builtins.float]'
promotion of types
by the mypy
.For example, int
is not a subtype of float
in runtime, but the mypy
considers it so. And wherever float
is expected, an int
can be passed (sometimes it may not be obvious), although it is not a subtype of it.
Union
for class attributesclass A:
x: Union[bool, int, float]
reveal_type(A.x) # Revealed type is 'builtins.float'
This result is because bool
is a subtype of int
and int
is promoted to float
by the mypy
.
In your example for TypedDict
, there is a Union
simplifying, like below
from typing import Union, TypedDict
D = TypedDict("D", {"x": Union[int, float]})
d: D
y: Union[int, float]
reveal_type(d["x"]) # Revealed type is 'builtins.float'
reveal_type(y) # Revealed type is 'Union[builtins.int, builtins.float]'
Upvotes: 2