I have this piece of code:
from typing import NamedTuple
class KeyTuple(NamedTuple):
key: str
storage: dict[KeyTuple, int] = {}
storage.get(("kek",))
that raises an error:
test_mypy.py:8: error: No overload variant of "get" of "dict" matches argument type "Tuple[str]" [call-overload]
test_mypy.py:8: note: Possible overload variants:
test_mypy.py:8: note: def get(self, KeyTuple, /) -> Optional[int]
test_mypy.py:8: note: def [_T] get(self, KeyTuple, Union[int, _T], /) -> Union[int, _T]
But if I try with:
storage: dict[tuple[str], int] = {}
storage.get(("kek",))
mypy doesn't raise any errors.
I expected no errors with the NamedTuple variant.
Unlike with, say,
dictandtyping.TypedDict, a regular tuple is never an instance of a namedtuple class. After all, a regular tuple's elements can't be accessed by name. A namedtuple class is a tuple subclass that adds additional functionality.When you annotate your dict as
dict[KeyTuple, int], you tell mypy that all keys will be of typeKeyTuple. Unlike, say, a JavaMap, this applies to retrieval operations, too, not just insertion. It is a static typing error to try to calldict.getwith a key of the wrong type. Since a regular tuple is not an instance ofKeyTuple,storage.get(("kek",))is invalid.Either call
getwith aKeyTuple:or annotate your dict as having regular tuple keys: