I have a base class:
class MyBaseClass:
@abstractmethod
def from_list(list_float: List[float]) -> Self:
pass
@staticmethod
@abstractmethod
def fn() -> int:
pass
All children of that class implement from_list
and static fn
, since they are abstract.
Now, I have another class 'MyOptions' :
class MyOptions:
@abstractclass
def related_to_type(): type(MyBaseClass)
All MyOptions
children implement related_to_type
, which returns a type that is a child of MyBaseClass
. What I want is:
Provided a MyOptions
child (which is unknown until runtime), call fn
on its related type, returned by related_to_type()
. In other term, I want:
options: MyOptions = MyOptionChild()
type_opt = options.related_to_type() # this should return a MyBaseClass child type
result = type_opt.fn() # error here
The error is that type_opt
contains an variable of type <class 'abc.ABCMeta'>
, on which I cannot call my static function fn
.
PS : I cannot make MyOptions generic with a type argument because the related type is known at run-time only
What can I do to call a static function on a variable containing a "reflected class" in Python ? Typically, in java, you would do:
Method method = myBaseClassChild.getMethod("fn");
int result = method.invoke(null);
Your MyOptionChild
needs to return a concrete type that implements fn
; it's not clear from your pseudocode whether you did this in your actual code, but it should "just work".
You can use Generic
to type-annotate it in such a way that a function can take an arbitrary MyOptions
and do reasonable things with its associated MyBaseClass
, and a type-checker can validate that the appropriate interfaces are being used.
Here's a working example:
from abc import abstractmethod
from typing import Generic, Type, TypeVar
class MyBaseClass:
@staticmethod
@abstractmethod
def fn() -> int:
pass
_MyBaseClass = TypeVar("_MyBaseClass", bound=MyBaseClass)
class MyOptions(Generic[_MyBaseClass]):
@abstractmethod
def related_to_type(self) -> Type[_MyBaseClass]:
pass
def call_fn(options: MyOptions) -> int:
return options.related_to_type().fn()
# Everything before this line deals with abstract types.
# Now the concrete implementations:
class MyChildClass(MyBaseClass):
@staticmethod
def fn() -> int:
return 42
class MyOptionChild(MyOptions[MyChildClass]):
def related_to_type(self) -> Type[MyChildClass]:
return MyChildClass
# Now call_fn with our concrete MyOptionChild:
print(call_fn(MyOptionChild())) # 42