问题
I have a class that inherits from typing.Generic
and passes in one TypeVar
as the parameter.
Later on in the code, I would like to:
- Statically (not at runtime) get the
TypeVar
parameter out from the class - Alias it to another type variable
- Use that alias to type hint the
return
of a function
Is there some way in Python that I can make this happen?
The only piece I am missing is step 1, how to get the type parameter out of a type variable
My Use Case
from abc import ABC, abstractmethod
from typing import TypeVar, Generic
TFloat = TypeVar("TFloat", bound=float)
class BaseDataClass(Generic[TFloat], ABC):
@property
@abstractmethod
def data(self) -> TFloat:
"""Get data."""
class ChildDataClass(BaseDataClass[int]):
@property
def data(self) -> int:
return 1
I then import BaseDataClass
and ChildDataClass
into another module.
In that second module, is there some way to statically get the TFloat
parameter from BaseDataClass
, or the int
parameter from ChildDataClass
, and use it in mypy
?
FYI: I am using Python 3.8.2.
回答1:
There isn't a way of "getting" out a type variable. You shouldn't think of a type variable as being like a chunk of data you can potentially extract somehow. Instead, think of it as a part of a definition.
I think based on your question, what you're really after is a way of writing a function that accepts some BaseDataClass[T]
(or a subclass of this type) and returns whatever T
is.
If so, create a function that matches the definition of whatever you want to accept. But instead of specifying that the inner type must be something specific, capture it using a generic instead.
In this case, we chose to match against anything of type BaseDataClass[T]
, where we keep T generic. And our return type will be whatever T happened to match up against.
from typing import TypeVar
from other_module import BaseDataClass, ChildDataClass
T = TypeVar('T', bound=float)
def extract(wrapper: BaseDataClass[T]) -> T:
return wrapper.data
# BaseDataClass[FloatSubclass] exactly matches against BaseDataClass[T],
# and so T will be FloatSubclass in 'extract(x)' call.
class FloatSubclass(float): pass
x: BaseDataClass[FloatSubclass]
reveal_type(extract(x)) # Mypy displays "FloatSubclass"
# ChildDataClass doesn't exactly match BaseDataClass[T], but the child
# class *is* a subtype of BaseDataClass[int], which does match.
x: ChildDataClass
reveal_type(extract(x)) # Mypy displays "int"
For more details and examples, see the mypy docs on generics.
来源:https://stackoverflow.com/questions/62354233/how-to-statically-get-typevar-parameters-from-a-generic-for-use-in-static-type-c