我正在尝试为类_class1_
(可能是另一个类)创建一个包装,该类将在包含多个_class1_
实例的列表中,一些额外的变量,一些将与此列表一起操作的函数,并且还包装了(几乎)_class1_
的所有函数,实际上应该只是使用同一组参数为列表中存储的所有_class1_
对象调用相应的函数。
谁能提出更好的方法来做到这一点,然后手动实现所有这些函数(将遍历列表并从List_class1
调用相应的函数)?
例
class class2:
def __init__(self, N):
self._N = N
self.List_class1 = []
for i in range(0, self._N):
self.List_class1.append(class1())
def function1(self, params)
for i in range(0, self._N):
List_class1[i].function1(params)
def function2(self, params)
ret = []
for i in range(0, self._N):
ret.append(List_class1[i].function2(params))
return ret
因此,如果在 class1 中有许多我想要适应的函数,也许有人可以建议一种方法来重写?
首先,关于这段代码有很多不正确的地方,或者至少很奇怪:
- 你有一个共享类属性
__N
保存一个空列表——但在__init__
中,你立即用一个同名的实例变量隐藏它,大概包含一个数字。因此,该类属性永远不会执行任何操作。 - 也没有理由称它为
__N
。双下划线的唯一原因是当您需要防止超类或子类意外地对不兼容的内容使用相同的名称时。 - 您正在使用另一个共享类属性
List_class1
,但您正在__init__
中初始化它。例如,对于向类注册类的所有实例等情况,这是有意义的,但对于您尝试为每个实例创建列表的情况则没有意义。当你构造十几个class2(10)
时,你希望每个实例都有 10 个class1
实例,而不是所有实例共享相同的 120 个实例,对吧? - 您的
function1
和function2
不是方法,不能调用,因为它们不需要self
。或者,更确切地说,他们确实采取了self
,但以不寻常的名字params
.这意味着它们最终将self
作为参数传递给class1
中的每个函数。
无论如何,看起来您要做的是创建一种通用代理,但是它对对象列表执行"扇出"代理,而不仅仅是代理单个对象。
因此,通用代理的相同基本技术将起作用。
例如,您可以使用__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())
这将打印[5, 5, 5]
,然后["function 2!", "function 2!", "function 2!"]
.
或者,由于您只想保存class1
实例,因此可以静态执行此操作。这样做的好处是class2.function2
将是您可以在__dict__
中看到的真实方法,因此您的交互式解释器可以自动完成它,等等。
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])
好吧,最后一个可能更漂亮一点,而不是可怕的单行本,但希望你明白了。
一种适合您的方法是重写包装类的__getattr__
方法。当找不到实例属性时(即主类中包装器中未实现的任何函数),将调用此函数。
有关类似内容,请参阅此问题,但仅适用于单个类而不是它们的列表。
class Thing:
def __init__(self, name):
self.name = name
def func_1(self):
print(f"func_1: {self.name}")
def func_2(self):
print(f"func_2: {self.name}")
class AttributeGroup:
def __init__(self):
self.attributes = []
def add_attribute(self, function):
self.attributes.append(function)
def __call__(self, *args, **kwargs):
for attr in self.attributes:
attr(*args, **kwargs)
class AllThings:
things = []
def __getattr__(self, key):
attrs = AttributeGroup()
for thing in self.things:
attrs.add_attribute(thing.__getattribute__(key))
return attrs
group = AllThings()
group.things.append(Thing('a'))
group.things.append(Thing('b'))
group.func_1()
group.func_2()
AllThings
类中的__getattr__
方法应返回单个属性,因此FunctionGroup
类仅将调用传递给它收集的所有函数。
上面的代码应该打印:
func_1: a
func_1: b
func_2: a
func_2: b
然后,您还可以以某种方式使属性组类可迭代,以便您可以在列表中获取所有属性,而不仅仅是能够调用所有函数
# AttributeGroup class
def __getitem__(self, item):
return self.attributes[item]
# main
for each in group.name:
print(each)
指纹:
a
b