What you're looking for is typically referred to as a mixin. Take these classes for example.
class FooBase:
def data(self):
return "foo"
class BarBase:
def data(self):
return "bar"
Both define data
method but are themselves different classes. If we wanted to provide some mixin class that can print the value from data
we could do so like this:
from abc import ABC, abstractmethod
class PrintDataMixin(ABC):
@abstractmethod
def data(self):
pass
def print_data(self):
print(self.data())
Here we're saying that the PrintDataMixin
mixin can be applied to any class that has a data
method implemented. FooBase
and BarBase
could have completely different sets of methods defined, but as long as they have the data
method defined they will satisfy usage with PrintDataMixin
.
Example usage for extending FooBase
and BarBase
with this mixin:
class FooImpl(FooBase, PrintDataMixin):
pass
class BarImpl(BarBase, PrintDataMixin):
pass
FooImpl().print_data()
BarImpl().print_data()
foo
bar
Update:
You could try to do this more generically any point you want, but in general I find dynamic classes like that hard to work with especially when you need to debug the application. It also makes it harder for static analyzers like mypy to determine if you are using classes correctly.
It's much easier to determine what's going on when classes are well defined in the source.
To dynamically create a class with a mixin applied you could do something like this:
def class_of(*cls):
class NewClass(*cls):
pass
return NewClass
class_of(BaseClass, MixinClass)(*args, **kwargs).print_data()