我正在尝试为类_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中有一个我想适应的函数,也许有人可以提出一种方法来重写它?
答案 0 :(得分:0)
对您有用的一种方法是为包装器类覆盖__getattr__
方法。当找不到实例属性时(即,在主类中未在包装器中实现的任何函数),将调用此方法。
请参阅this question,以了解类似内容,但仅针对单个类而不是其列表。
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()
__getattr__
类中的AllThings
方法应返回单个属性,因此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
答案 1 :(得分:0)
首先,关于此代码的很多事情都是不正确的,或者至少是怪异的:
__N
,其中包含一个空列表;但是,在__init__
中,您会立即使用一个具有相同名称的实例变量(大概包含一个数字)将其隐藏。因此,该class属性永远不会做任何事情。__N
。出现双下划线的唯一原因是,当您需要防止超类或子类意外使用不兼容的同名名称时。List_class1
,但正在__init__
中对其进行初始化。这对于例如在该类中注册一个类的所有实例的情况是有意义的,但是对于试图为每个实例创建列表的情况则没有意义。当构造十二个class2(10)
时,您希望每个实例具有10个class1
实例,不是所有实例都共享相同的120个,对吗?function1
和function2
不是方法,也不能被调用,因为它们不占用self
。或者,相反,他们要做采取self
,但使用不寻常的名称params
。这意味着他们最终将self
作为参数传递给class1
中的每个函数。无论如何,看起来您正在尝试创建一种通用代理,但是该代理对对象列表执行“扇出”代理,而不是仅对单个对象进行代理。 / p>
因此,通用代理的相同基本技术将起作用。
例如,您可以使用__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])
好的,最后一个可能会更漂亮,而不是可怕的单线,但希望您能明白。