Repository navigation
Widening generic types when calling methods in context. #2108
Replies: 2 comments 1 reply
|
I think the key issue is that Python's current typing system doesn't provide a general way to infer a wider return type from the expected type at the call site. For this example, I'd keep from typing import cast
y = cast(dict[str | int | list, int], join(left, right))This works as a workaround, but Ideally, the type system would allow the return type's type variables to be inferred from both the arguments and the expected return type. That would preserve the precise |
|
I think the issue is partly due to One possible workaround is to accept a covariant protocol instead, since we're only reading from the inputs: from collections.abc import Iterable
from itertools import chain
from typing import Protocol
class SupportsItems[K, V](Protocol):
def items(self) -> Iterable[tuple[K, V]]: ...
def join[K, V](
left: SupportsItems[K, V],
right: SupportsItems[K, V],
) -> dict[K, V]:
return dict(chain(left.items(), right.items()))This may work for It doesn't solve the |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
I am wondering if there is a general recipe to annotate methods that return a new instance, so that it allows widening the type based on the outer context.
Question: Is it possible, in the current type system as of python 3.14, to annotate this method:
such that the following test passes without type errors
Context
Consider the following example:
According to PEP 584 – Add Union Operators To dict,
x | yis essentially equivalent to{**x, **y}, so the first surprise here is that the type checkers except formypyaccept one but not the other. This can be due to special casing of the literal constructor.However, it raises the question of how to communicate to the type checker when a method returns a new instance, and widening the type is OK.
My Attempt
The best I could come up with was adding a "slack-variable" to the output, but it doesn't work. I hoped that a type checker would infer
K :> objectif necessary, and so allowy: dict[object, int] = join(left, right), but none of the type checkers I tested allows this. Onlytyseems to partially accept this, but requires getting rid of the defaultK=Neverand consequently emitsdict[Unknown | int | str, Unknown | inton thereveal_typeMy current thinking is that this possibly requires HKT (#548), or more specifically lower bounding a
TypeVarby anotherTypeVar, so that for example the join method could be typed as:All reactions