First, there are a lot of things about this code that are incorrect, or at least weird:
- You have a shared class attribute
__N
holding an empty list—but in __init__
, you immediately hide that with an instance variable of the same name, presumably holding a number. So, that class attribute is never going to do anything.
- There's also no reason for it to be called
__N
. The only reason for double underscores is when you need to protect against superclasses or subclasses accidentally using the same name for something incompatible.
- You're using another shared class attribute
List_class1
, but you're initializing it in your __init__
. This makes sense for cases like, e.g., registering all instances of a class with the class, but it doesn't make sense for cases where you're trying to create a list per instance. When you construct a dozen class2(10)
s, you want each one to have 10 class1
instances, not all of them to share the same 120, right?
- Your
function1
and function2
aren't methods, and can't be called, because they take no self
. Or, rather, they do take a self
, but under the unusual name params
. Which means they end up passing self
as the params to every function in class1
.
Anyway, it looks like what you're trying to do is create a sort of generic proxy, but one that does a "fan-out" proxy to a list of objects, instead of just proxying to a single object.
So, the same basic techniques for generic proxies will work.
For example, you can do it dynamically with __getattr__
:
class class2:
def __init__(self, N):
self.c1s = [class1() for _ in range(N)]
def __getattr__(self, name):
if name.startswith('_'):
raise AttributeError(name)
methods = []
for c1 in self.c1s:
attr = getattr(c1, name)
if callable(attr):
methods.append(attr)
if methods:
def _map(*args, **kw):
return [method(*args, **kw) for method in methods]
return _map
raise AttributeError(name)
class class1:
def function1(self, x, y):
return x+y
def function2(self):
return 'function 2!'
c2 = class2(3)
print(c2.function1(2, 3))
print(c2.function2())
This will print [5, 5, 5]
and then ["function 2!", "function 2!", "function 2!"]
.
Or, since you only want to hold class1
instances, you can do it statically. This has the advantage that class2.function2
will be a real method that you can see in the __dict__
, so your interactive interpreter can autocomplete it, etc.
class class2:
def __init__(self, N):
self.c1s = [class1() for _ in range(N)]
for name, value in inspect.getmembers(class1, callable):
if name.startswith('_'):
continue
setattr(class2, name, lambda self, *args, _v=value, **kw: [_v(c1, *args, **kw) for c1 in self.c1s])
OK, that last one could probably be a bit prettier instead of a horrible one-liner, but hopefully you get the idea.