我有一个包含如下列表的类:
class Zoo:
def __init__(self):
self._animals = []
我用具有各种属性的动物对象填充动物列表:
class Animal:
def __init__(self, speed, height, length):
self._speed = speed
self._height = height
self._length = length
您可以想象Animal具有其他属性的子类。我希望能够编写执行相同计算但对Animal的不同属性执行的方法。例如,平均值。我可以在Zoo中编写以下内容:
def get_average(self, propertyname):
return sum(getattr(x, propertyname) for x in self.animals) / len(self.animals)
该字符串查找不仅使我无法很好地记录文档,而且使用getattr
似乎很奇怪(也许我只是紧张地传递字符串?)。如果这是一种好的标准做法,那很好。创建get_average_speed()
,get_average_height()
和get_average_length()
方法(尤其是在我添加更多属性时)似乎也不明智。
我意识到我想在此示例中封装单线,但是是否有更好的方法去基于Zoo列表中对象的属性来创建这样的方法?我稍微看了一些工厂功能,所以当我对它们的理解更好时,我想我可以写这样的东西:
all_properties = ['speed', 'height', 'length']
for p in all_properties:
Zoo.make_average_function(p)
然后,任何Zoo实例都将具有名为get_average_speed()
,get_average_height()
和get_average_length()
的方法,最好使用漂亮的文档字符串。更进一步,我真的很喜欢Animal对象本身告诉我的Zoo哪些属性可以转换为get_average()
方法。到最后,假设我将Animal子类化,并希望它表明它创建了一个新的average方法:(以下是伪代码,我不知道是否可以这样使用装饰器)
class Tiger(Animal):
def __init__(self, tail_length):
self._tail_length = tail_length
@Zoo.make_average_function
@property
def tail_length(self):
return self._tail_length
然后,在将Tiger添加到Zoo时,我将动物添加到Zoo对象的方法将知道为Zoo实例创建get_average_tail_length()
方法。动物型对象不必保留我需要制作的平均方法的列表,而可以表示可以平均的东西。
是否有一种很好的方法来生成这种方法?还是除了getattr()
之外还有另一种说法是“对列表中每个成员的特定属性进行一些计算/工作”?
答案 0 :(得分:1)
尝试一下:
import functools
class Zoo:
def __init__(self):
self._animals = []
@classmethod
def make_average_function(cls, func):
setattr(cls, "get_average_{}".format(func.__name__), functools.partialmethod(cls.get_average, propertyname=func.__name__))
return func
def get_average(self, propertyname):
return sum(getattr(x, propertyname) for x in self._animals) / len(self._animals)
class Animal:
def __init__(self, speed, height, length):
self._speed = speed
self._height = height
self._length = length
class Tiger(Animal):
def __init__(self, tail_length):
self._tail_length = tail_length
@property
@Zoo.make_average_function
def tail_length(self):
return self._tail_length
my_zoo = Zoo()
my_zoo._animals.append(Tiger(10))
my_zoo._animals.append(Tiger(1))
my_zoo._animals.append(Tiger(13))
print(my_zoo.get_average_tail_length())
注意:如果不同的动物园里有不同类型的动物,则会导致混乱。
示例
class Bird(Animal):
def __init__(self, speed):
self._speed = speed
@property
@Zoo.make_average_function
def speed(self):
return self._speed
my_zoo2 = Zoo()
my_zoo2._animals.append(Bird(13))
print(my_zoo2.get_average_speed()) # ok
print(my_zoo.get_average_speed()) # wrong
print(my_zoo2.get_average_tail_length()) # wrong