-
Trying to learn how to write statically typed Python, but got confused for quite some time. Here is a toy example: from typing import TypedDict
from collections.abc import Mapping
# represent the loose idea of a point as a mapping (i.e. dict or variants) from coordinates to floats
type PointLike = Mapping[str, float]
# a specific type of point
class Point2D(TypedDict):
x: float
y: float
# other types of points may be defined here or elsewhere (thanks to duck typing)
# examples: 3D space, RGB...
# the point (pun intended) is to implement transformations between different point types
# those should be abstracted with a Protocol later on
# here is a trivial transformation
def identity_transform[T: PointLike](p: T) -> T:
# return the point unchanged
return p
# let's test it
my_point = Point2D(x=0.7, y=-0.3)
identity_transform(my_point) # runs fine, but type checker error! Both mypy and pyright will error on the last line, as can be seen in the playground links provided. My main question is: why is this? After thinking about it for way too long, my guess would be that, since Python dictionaries are mutable, there is nothing stopping you from adding another key of a different type to A second question is: what would, then, be the appropriate way to implement the idea in the problem while keeping static type checkers happy? |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
To understand why your There is a draft PEP 728 that proposes to add the concept of "closed TypedDicts" to the type system. Pyright has experimental support for this PEP if you want to play around with it. Here's what that looks like in the pyright playground. |
Beta Was this translation helpful? Give feedback.
To understand why your
TypedDict
isn't assignable toMapping[str, float]
, check out this section of the typing spec. (Scroll down to the last bullet point in that section.)There is a draft PEP 728 that proposes to add the concept of "closed TypedDicts" to the type system. Pyright has experimental support for this PEP if you want to play around with it. Here's what that looks like in the pyright playground.