将多个类方法应用于对象列表的Pythonic方式
我有一个带有一些内置方法的类。这是该类的抽象示例:
class Foo:
def __init__(self):
self.a = 0
self.b = 0
def addOneToA(self):
self.a += 1
def addOneToB(self):
self.b += 1
为简单起见,我将内置方法总数减少到 2 个,但实际上我的类有接近 20 个。
接下来,我有另一个类,旨在处理Foo实例列表。
class Bar:
def __init__(self, fooInstances):
self.fooInstances = fooInstances
# Bar([Foo(), Foo(), Foo()])
如果我想将其中一种Foo方法应用于 中的Foo实例Bar怎么办?
class Bar:
# ...
def addOneToA(self):
for fooInstance in self.fooInstances:
fooInstance.addOneToA()
def addOneToB(self):
for fooInstance in self.fooInstances:
fooInstance.addOneToB()
上面的例子是我描述的一种方法,但是如果有 20 个Foo. 或者,我可以做这样的事情:
class Bar:
# ...
def applyFooMethod(self, func, *args):
for fooInstance in self.fooInstances:
fooInstance.func(args)
但我宁愿有一些会允许我这样称呼.addOneToA()上Bar,并把它应用到所有Foo的情况Bar。有没有一种干净的方法来做到这一点而无需定义Fooinside 的所有方法Bar?
回答
一种方法是覆盖__getattr__的Bar:
class Bar:
def __init__(self, fooInstances):
self.fooInstances = fooInstances
def __getattr__(self, attr):
try:
getattr(self.fooInstances[0], attr)
except AttributeError:
raise AttributeError(f"'Bar' object has no attribute '{attr}'")
else:
def foo_wrapper(*args, **kwargs):
for foo_inst in self.fooInstances:
getattr(foo_inst, attr)(*args, **kwargs)
return foo_wrapper
__getattr__Bar如果对Bar对象的属性查找失败,则调用 on 。然后我们尝试查看一个Foo实例是否具有该属性;如果没有,则提出一个,AttributeError因为既不Bar也不Foo接受该属性。但是,如果Foo确实有它,我们将返回一个函数,该函数在调用时会在驻留在object 中的attr每个瞬间调用方法 ( ) 。FooBar
用法:
...
# changed this method in Foo to see the passing-an-argument case
def addOneToA(self, val):
self.a += 1
print(f"val = {val}")
...
>>> bar = Bar([Foo(), Foo(), Foo()])
>>> bar.addOneToB()
>>> [foo.b for foo in bar.fooInstances]
[1, 1, 1]
>>> bar.addOneToA(val=87) # could also pass this positionally
val = 87
val = 87
val = 87
>>> bar.this_and_that
AttributeError: 'Bar' object has no attribute 'this_and_that'