Description
Description & motivation
Allow widening type subscriptions for annotations beyond the type var bound, if the type var is covariant.
Consider the type Box[T: Boxable]
(see example section below for more details), where T
is covariant. The Boxable
bound could be a union or some abstract type. The bound is typically relevant for the implementation of the class, or to constrain subclasses' concrete types. Essentially, for all concrete use cases, the bound is important.
However, type annotations are more of an abstract case. Considering that the type var is covariant, it should allow us to widen the bound. In a context that doesn't care about the specifics of what is allowed, or even a context that doesn't want to get involved with such details, it could be more readable (and still correct I believe) to generalize.
Specifically, I would be very interested in the ability to use the top type object
to declare I don't care about which concrete instantiation of Box
I get, and I'm in a context where I don't even care or want to get involved with which concrete types are allowed for T
.
Example
type Boxable = int | str
"""
Concrete types that are supported in a box. Important for concrete, runtime cases, e.g. they must be serializable.
"""
class Box[T: Boxable]:
"""
Immutable box for a value. Concrete boxes
"""
def __init__(self, x: T) -> None:
self.x = x
def get(self) -> T:
return self.x
# I don't care what box allows, I can print anything and I want to keep my interface simple.
def print_contents(box: Box[object]) -> None:
"""
Print contents of a box.
"""
print(box.get())
Mypy raises an error for the box: Box[object]
annotation that 'Type argument "object" of "Box" must be a subtype of "int | str"'. I believe that this is too restrictive. As motivated in the comment above the function, this is a context where we don't care about Box
's constraints or invariants. Only that it contains some object. In practice this will always be a Boxable
, but this function doesn't need to know about that.
Notes
- This feature request may be impossible at the moment, due to Use case for typing.Type with abstract types #4717 (comment).
- In Python 3.13 I could probably get something close to what I describe in my example use case by using type var defaults. So that decreases the relevance, but even then I might occasionally want to express the simplified generalization
object
for readability purposes.