What is an alternative for TypeVar.__class_getitem__

Considering this example

from typing import TypeVar

_K = TypeVar("_K")
_V = TypeVar("_V")

class D(dict[_K, _V]):
    ...

reveal_type(D.fromkeys(range(1)))

Both mypy and pyright think that the type is builtins.dict, not D. Moreover, defaultdict.fromkeys is not present in typeshed, so result type is also builtins.dict, but not for other dict-like types in collections.

This works like that because there is no way to annotate dict.fromkeys to return actual type of first argument instead of dict. So, my question is why we can not subscribe TypeVar, so we can annotate such cases as

_Self = TypeVar("_Self", bound="dict")  # or typing.Self
class dict(Generic[_K, _V]):
    def classmethod(
        cls: type[_Self], 
        iterable: Iterable[_TK],
        value: _TV
    ) -> _Self[_TK, _TV]: ...

My use-case does not involve dicts, so it is general typing question. My case can be simplifyed to example from Descriptors HowTo

class Field(Generic[T_get, T_set]):
    def __init__(self, converter=None):
        self.private_name = None
        self.converter = converter

    def __set_name__(self, owner, name):
        self.private_name = '_' + name

    def __get__(self, obj, objtype=None) -> T_get:
        result = getattr(obj, self.private_name)
        if self.converter is not None:
            result = self.converter(result)
        return result

    def __set__(self, obj, value: T_set):
        self.validate(value)
        setattr(obj, self.private_name, value)

    @abstractmethod
    def validate(self, value):
        pass

    def with_coverter(
        self: Self, converter: Callable[[T_set], T_get]
    ) -> Self[T_get, T_set]:
        result = copy.copy(self)
        result.converter = converter
        return result

Right now if I want to have correct return type of with_coverter in subclasses I need to add correct signature with return super.

It sounds like you’re looking for higher-kinded TypeVars. (See this long-standing feature request.) This is a feature I’d be very interested in seeing come to Python’s typing system at some point. However, it would be an extremely complex feature to implement, so many things would have to be thought through.

(I don’t have the bandwidth to push for this feature right now. I’m also not sure if it should be the feature we “prioritise next” when it comes to expanding the type system :slight_smile: )

1 Like