Python:具有对象列表的对象 - 基于列表成员的属性创建方法

Peb*_*bby 5 python attributes list object python-3.x

我有一个包含如下列表的类:

class Zoo:
    def __init__(self):
        self._animals = []
Run Code Online (Sandbox Code Playgroud)

我使用具有各种属性的动物对象填充动物列表:

class Animal:
    def __init__(self, speed, height, length):
        self._speed = speed
        self._height = height
        self._length = length
Run Code Online (Sandbox Code Playgroud)

您可以想象具有其他属性的Animal的子类.我希望能够编写执行相同计算但在Animal的不同属性上的方法.例如,平均值.我可以在Zoo中编写以下内容:

def get_average(self, propertyname):
    return sum(getattr(x, propertyname) for x in self.animals) / len(self.animals)
Run Code Online (Sandbox Code Playgroud)

那个字符串查找不仅仅是因为我能够很好地记录,但是使用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)
Run Code Online (Sandbox Code Playgroud)

然后动物园的任何实例都会有所谓的方法get_average_speed(),get_average_height()以及get_average_length(),最好有好的文档字符串.更进一步,我真的很喜欢Animal对象本身告诉我的动物园什么属性可以变成get_average()方法.最后,让我说我是Animal的子类,并希望它表明它创建了一个新的平均方法:( 以下是伪代码,我不知道装饰器是否可以像这样使用)

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
Run Code Online (Sandbox Code Playgroud)

然后,在向动物园添加Tiger时,我将动物添加到Zoo对象的get_average_tail_length()方法将知道为Zoo的该实​​例创建方法.动物类型的对象不是必须保留我需要制作的平均方法的列表,而是指示可以平均的事物.

有没有一种很好的方法来生成这种方法?或者除了getattr()说"对这个列表中每个成员的特定属性做一些计算/工作" 之外还有另一种方法吗?

Mad*_*Lee 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())
Run Code Online (Sandbox Code Playgroud)

注意:如果不同动物园有不同种类的动物,会导致混乱。

例子

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
Run Code Online (Sandbox Code Playgroud)