-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Description
(There are a couple of other issues that I think might be the same thing as this question, but I'm not sure, because they're posed at a lower level—apologies if this is actually a duplicate. #3153, maybe?)
The generic methods and generic self docs show how write a class with methods that accept/return arguments of the most precise type, so things like this work as intended:
from typing import Generic, TypeVar
T = TypeVar('T', bound='Modular')
### this works! yay!
class Modular(object):
modulus = 0 # type: int
def __init__(self, i):
# type: (int) -> None
self.i = i % self.modulus
def __add__(self, other):
# type: (T, T) -> T
return self.__class__((self.i + other.i) % self.modulus)
class Mod5(Modular):
modulus = 5
class Mod6(Modular):
modulus = 6
Mod5(3) + Mod6(3) # statically "disallowed"
mypy won't let me add Mod5
s to Mod6
s, hooray. But what if the relevant class is itself generic? This doesn't work:
In = TypeVar('In', contravariant=True)
Out = TypeVar('Out', covariant=True)
A = TypeVar('A')
B = TypeVar('B')
F = TypeVar('F', bound='FunctionLike')
class FunctionLike(Generic[In, Out]):
def call(self, arg):
# type: (In) -> Out
raise NotImplementedError
def compose(self, other):
# type: (F[In, Out], F[Out, B]) -> F[In, B] # can't index `F`, so this doesn't work
raise NotImplementedError
The type of compose
shouldn't be (FunctionLike[In, Out], FunctionLike[Out, B]) -> FunctionLike[In, B]
, because then any two instances of any two subclasses could be composed together. It can't be (F, F) -> F
because then all the type parameters are the same.
Is there a way to express this?