SuperShoot
SuperShoot

Reputation: 10872

Mypy: Type of dict value doesn't change with assignment while type of variable does

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

Answers (1)

alex_noname
alex_noname

Reputation: 32233

This is due to some mypy features:

  • Type narrowing for 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]'
  • The so-called 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.

  • Simplifying of Union for class attributes
class 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

Related Questions