I have a class like:
class ExampleClass(BaseClass[Someclass]):
pass
class BaseClass(AbstractBaseClass, Generic[T]):
pass
I want to be able to do something like ExampleClass.targetType where I will return Someclass.__name__ how can I do this inside BaseClass I cannot seem to do T.__name__
I can workaround by defining a method like
class ExampleClass(BaseClass[Something]):
version = 1
def get_target_class_name() -> str:
return Something.__name__
But I will need to copy this for every class
You can define a metaclass:
from typing import Generic, TypeVar
T = TypeVar("T")
class AbstractBaseClass:
pass
class BaseClassMeta(type):
def __init__(cls, name, bases, attrs):
assert "target_type" not in attrs
if len(attrs["__orig_bases__"]) == 1:
base, = attrs["__orig_bases__"]
if args := getattr(base, "__args__", None):
cls.target_type = args
return super().__init__(name, bases, attrs)
class BaseClass(AbstractBaseClass, Generic[T], metaclass=BaseClassMeta):
pass
class TargetClass():
pass
class ExampleClass(BaseClass[TargetClass]):
pass
print(ExampleClass().target_type) # TargetClass
This will make all subclasses of BaseClass that have a single superclass which has a single generic parameter have an attribute target_type, set to that parameter. This will be available to instances of the class too, and subclasses.
You can make use of typing.get_args and __orig_bases__.
get_args will give you the arguments of a type:
assert get_args(Dict[int, str]) == (int, str)
and __orig_bases__ stores the original bases as a tuple. In the context of the example code below
assert Derived.__orig_bases__ == (Base[int],)
so the resulting code would be something like:
from abc import ABC
from typing import Generic, TypeVar, get_args
T = TypeVar("T")
class Base(ABC, Generic[T]):
def target_type(self) -> str:
return get_args(self.__orig_bases__[0])[0].__name__
class Derived(Base[int]):
pass
d = Derived()
print(d.target_type())
# prints 'int'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With