0

I am having a hard time using python typing annotations when dealing with generics and compound types

Consider the following class:

import typing as ty

T = ty.TypeVar("T")
CT = tuple[bool, T, str]

class MyClass(ty.Generic[T]):
    internal1: tuple[bool, T, str]
    internal2: CT[T]
    internal3: CT[float]

class DerivedMyClass(MyClass[float]):
    pass

print(ty.get_type_hints(MyClass))
print(ty.get_type_hints(DerivedMyClass))

where the type of internal 1, 2, 3 is actually a much more lengthy type annotation. The output is:

{
'internal1': tuple[bool, ~T, str], 
'internal2': tuple[bool, ~T, str], 
'internal3': tuple[bool, float, str]
}
{
'internal1': tuple[bool, ~T, str], 
'internal2': tuple[bool, ~T, str], 
'internal3': tuple[bool, float, str]
}

Is there a way to make CT aware of the type in the derived class?

Hernan
  • 5,811
  • 10
  • 51
  • 86

1 Answers1

0

If you are able to use Pydantic, this can be pretty easy:

import typing as ty
from pydantic.generics import GenericModel


T = ty.TypeVar("T")
CT = tuple[bool, T, str]

class MyClass(GenericModel, ty.Generic[T]):
    internal1: tuple[bool, T, str]
    internal2: CT[T]
    internal3: CT[float]


DerivedClass = MyClass[float]

print(ty.get_type_hints(DerivedClass))

This outputs:

{'__concrete__': typing.ClassVar[bool], 'internal1': tuple[bool, float, str], 'internal2': tuple[bool, float, str], 'internal3': tuple[bool, float, str]}

Without using pydantic, best of luck! (or read and copy the source code for GenericModel)

Tom McLean
  • 5,583
  • 1
  • 11
  • 36
  • Is this a limitation of Python typing semantics or implementation? – Hernan Feb 16 '23 at 15:00
  • @Hernan What do you mean? – Tom McLean Feb 16 '23 at 15:04
  • In other languages, the generic variable is not defined previously but contextually to the definition. Like in rust `fn largest(list: &[T]) -> &T` T does not mean anything outside the definition of fn. But in Python, we have to define something as `TypeVar` so it is always unclear how specialization work. The value of `T`is "fixed" while defining the class and not changed when specializing. It seems that what `GenericModel` would be given freely if the syntax and the semantics for generic in Python were different. i.e. if a `TypeVar` is contextual, specializing will clearly propagate. – Hernan Feb 18 '23 at 15:56
  • @Hernan No idea what you mean. Without subclassing from generic model, this class would keep T as the type. If you look in the very complicated source code, GenericModel replaces T with the type you specify when you do `MyClass[float]` – Tom McLean Feb 23 '23 at 15:40