`TypeVar`: parametric type as a value for `bound` parameter

Viewed 1389

I'd like to implement a generic class like this:

S = TypeVar("S")
T = TypeVar("T", bound=OtherParametrizedClass)

class MyClass(Generic[T[S]]):
    def some_method(param: S) -> None:
        pass

I've already tried the following:

S = TypeVar("S")
T = TypeVar("T", bound=OtherParametrizedClass)

class MyClass(Generic[S, T[S]]):
    def some_method(param: S) -> None:
        pass
    def other_method(param: T) -> None:
        pass

It works as expected with MyPy. However, when Python interpreter runs this code, it gives me the following error:

TypeError: 'TypeVar' object is not subscriptable.

As I found, this means that TypeVar has no [] operator implemented.

Does anyone have an idea on how to obtain the solution satisfying both mypy and Python interpreter?

EDIT: I have also tried the following:

S = TypeVar("S")
T = TypeVar("T", bound=OtherParametrizedClass[S])

class MyClass(Generic[T]):
    def some_method(param: S) -> None:
        pass
    def other_method(param: T) -> None:
        pass

Python interpreter doesn't give any errors/warnings. However mypy is complaining about the second line:

Invalid type "S"
1 Answers

I'm not sure I understand exactly what you're trying to achieve.

There are basically two questions:

  • why do you need to define T?
  • why is MyClass Generic[T] instead of Generic[S]?

The second question is key: I think fundamentally what you're getting wrong is that you're trying to make MyClass Generic[T], when it should simply be Generic[S], at which point you don't even need to define T. other_method can just return OtherParametrizedClass[S].

Below an example that I think does what you're trying to achieve:

import dataclasses
from typing import Generic, TypeVar

N = TypeVar("N", int, float)


@dataclasses.dataclass
class Adder(Generic[N]):
    to_add: N

    def add(self, value: N) -> N:
        return value + self.to_add


class Foo(Generic[N]):
    def get_adder(self, to_add: N) -> Adder[N]:
        return Adder(to_add)

Name mapping from my example to yours:

  • N is S
  • Adder is OtherParametrizedClass
  • Foo is MyClass
  • Foo.get_adder is MyClass.other_method
Related