6

I am trying to use a TypeVar to indicate an init parameter as a certain type. But I am doing it wrong, or it might not even be possible.

from typing import TypeVar T=TypeVar("T") class TestClass: def __init__(self,value:T): self._value=value a = TestClass(value=10) b = TestClass(value="abc") reveal_type(a._value) reveal_type(b._value) 

I was hoping the reveal type of a._value would have been int and b._value to have been string. But they are both revealed as 'T`-1'

Any help or insight appreciated!

[EDIT]

A little more expanded example. The BaseClass will be overridden and the actual type hint is provided by the overriding class.

from typing import TypeVar T=TypeVar("T") class BaseClass: def __init__(self,value): self._value = value class Class1(BaseClass): def __init__(self,value:str): super().__init__(value) class Class2(BaseClass): def __init__(self,value:int): super().__init__(value) a = Class1("A value") b = Class2(10) reveal_type(a._value) reveal_type(b._value) 
4
  • What did you even mean when you wrote that code? What did you expect the type variable to do? That's not how you use type variables. Commented Nov 17, 2020 at 10:39
  • Did you want TestClass to be generic or something? Commented Nov 17, 2020 at 10:40
  • I basically want the _value property to take the type of the value I assign it to. But it doesn't. Commented Nov 17, 2020 at 10:43
  • 1
    You must define TestClass as generic, i.e. class TestClass(Generic[T]):. Otherwise, the conrcete type of T is only scoped to the method and lost afterwards. Commented Nov 17, 2020 at 10:55

1 Answer 1

9

By default, using a TypeVar restricts its scope only to the method/function in which it is used as an annotation. In order to scope a TypeVar to the instance and all methods/attributes, declare the class as Generic.

from typing import TypeVar, Generic T=TypeVar("T") class BaseClass(Generic[T]): # Scope of `T` is the class: def __init__(self, value: T): # Providing some `T` on `__init__` self._value = value # defines the class' `T` 

This allows declaring subclasses either as generic or as concrete.

class Class1(BaseClass[str]): # "is a" BaseClass where `T = str` pass # No need to repeat ``__init__`` class ClassT(BaseClass[T]): # "is a" BaseClass where `T = T'` @property def value(self) -> T: return self._value reveal_type(Class1("Hello World")._value) # Revealed type is 'builtins.str*' reveal_type(Class1(b"Uh Oh!")._value) # error: Argument 1 to "Class1" has incompatible type "bytes"; expected "str" reveal_type(ClassT(42).value) # Revealed type is 'builtins.int*' 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.