Here's proof that not only is your question a duplicate like I said it was of that other one, but also that it indeed does solve the problem.
A metaclass approach is totally fitting because the essence of what you want to do is create new classes, and the instances of a metaclass are classes. The fact that these class instance are based on an existing ones means that it can be done "extending" or "wrapping" the methods of the existing one is an additional detail which making the answer to the duplicate question that much more suitable.
Also note that this technique is more generic and "automatic" than @juanpa.arrivillaga's answer in the sense that you don't have list the methods you want (since it does them all). And that it doesn't require changing class A
as you claimed in a comment — although I did change it from what's in your question in order to have something more suitable for development and testing proposes.
Also note that the classes created are subclasses of the the base class, A
in the example code, in terms of inheritance (not the metaclass).
from functools import wraps
from types import FunctionType
def wrapper(method):
@wraps(method)
def wrapped(self, *args, **kwargs):
for instance in self.base_instances:
method(instance, *args, **kwargs)
return wrapped
class MyMetaClass(type):
def __new__(meta, classname, bases, classdict):
assert len(bases) == 1, 'A single base class is required'
# Define an `__init__()` method.
Base = bases[0]
def __init__(self, n):
self.base_instances = [Base() for _ in range(n)]
# Create methods by wrapping those of base class.
new_classdict = {key: wrapper(value) if isinstance(value, FunctionType) else value
for key, value in vars(Base).items()
if isinstance(value, FunctionType)}
new_classdict['__init__'] = __init__ # Replace.
# Construct the class using new class dictionary.
return type.__new__(meta, classname, bases, new_classdict)
class A:
def __init__(self):
self.data = list(range(1, 5)) # Initialize self.data
def func1(self, *args, **kargs):
print(', '.join(str(i) for i in self.data)) # Do things with self.data
def func2(self, *args, **kargs):
print(f'sum: {sum(self.data)}') # Do things with self.data
# There are lots more functions like func1 & 2
...
class B(A, metaclass=MyMetaClass):
pass
b = B(3)
b.func1()
b.func2()