It’s not clear in PEP 695 whether private members of a class should be taken into account when variance of the class’s type-vars gets inferred. Pyright’s current implementation (v1.1.336) are using them all, but I personally think that they need to be excluded. What will be your thoughts?
For example –
class Translator[K, V]:
__dictionary: dict[K, V]
def __init__(self, dictionary: dict[K, V], /) -> None:
self.__dictionary = dictionary
def __getitem__(self, key: K, /) -> V:
return self.__dictionary[key]
I imagined that K would be contravariant and V would be covariant, because K is only used as input and V is only used as output. But in fact, K and V are both inferred as invariant, because __dictionary is typed as dict[K, V] and both arguments of dict are invariant.
What’s worse, even after re-typing __dictionary into collections.abc.Mapping –
from collections.abc import Mapping
class Translator[K, V]:
__dictionary: Mapping[K, V]
def __init__(self, dictionary: Mapping[K, V], /) -> None:
self.__dictionary = dictionary
def __getitem__(self, key: K, /) -> V:
return self.__dictionary[key]
K is still inferred as invariant instead of contravariant, because there are methods like keys and items on collections.abc.Mapping which return the key type and make it invariant.
To make this sample work as I expected, I need to add a custom protocol, with only __getitem__ method which I’m going to use, to further restrict the type of __dictionary. But I don’t think that should be required.