繁体   English   中英

如何创建一个基于继承类自动添加新聚合方法的集合类?

[英]How to create a collection class which automatically adds new aggregation methods based on inherited class?

我有一个类( Team ),它是另一个类( Player )的集合。 在最小的例子中,我只有一个Player property ,但我的现实世界代码有几十个更复杂的属性,我经常添加更多。

目前,每次我向Player添加新property时,我都需要手动向Team添加四个新属性,但我知道必须有更好的方法来做到这一点。 每次我在Player创建新property时,我都希望Team类自动添加这四个属性,从而大大减少了我需要编写的代码,但我不确定最好的方法。

from statistics import mean, median


class Player:
    def __init__(self, name, age):
        self.name = name
        self._age = age

    @property
    def age(self):
        return self._age


class Team:
    def __init__(self, players):
        self.players = players

    @property
    def all_ages(self):
        return {player.name: player.age for player in self.players}

    @property
    def total_age(self):
        return sum([player.age for player in self.players])

    @property
    def average_age(self):
        return mean([player.age for player in self.players])
        
    @property
    def median_age(self):
        return median([player.age for player in self.players])


p1 = Player('John', 8)        
p2 = Player('Tim', 9)        
p3 = Player('Annie', 11)        
team = Team([p1, p2, p3])

正如我在评论中所说,您的集合类和它包含的对象的类之间不涉及继承。 这意味着设置东西总是需要一定数量的繁琐重复编码——至少如果你按照下面所示使用类装饰器进行设置——但是一旦设置好,添加更多属性应该相对容易。

from statistics import mean, median


def make_stat_properties(team_cls, player_cls, name):
    storage_name = '_' + name

    @property
    def prop(self):
        return getattr(self, storage_name)
    @prop.setter
    def prop(self, value):
        setattr(self, storage_name, value)
    setattr(team_cls, name, prop)

    # Statistical methods.
    @property
    def all_func(self):
        return {getattr(player, 'name'): getattr(player, name) for player in self.players}
    func_name = f'all_{name}' if name.endswith('s') else f'all_{name}s'
    setattr(player_cls, func_name, all_func)

    @property
    def total_func(self):
        return sum(getattr(player, name) for player in self.players)
    setattr(player_cls, f'total_{name}', total_func)

    @property
    def average_func(self):
        return mean(getattr(player, name) for player in self.players)
    setattr(player_cls, f'average_{name}', average_func)

    @property
    def median_func(self):
        return median(getattr(player, name) for player in self.players)
    setattr(player_cls, f'median_{name}', median_func)

    return prop


class Team:
    def __init__(self, players):
        self.players = players


def stats_decorate(*names):
    def stats_prop_decorator(cls):
        """ Add stats properties to class. """
        for name in names:
            setattr(cls, name, make_stat_properties(cls, Team, name))
        def __init__(self, name, *args):
            self.name = name
            for name, arg in zip(names, args):
                setattr(self, f'_{name}', arg)
        setattr(cls, '__init__', __init__)
        return cls
    return stats_prop_decorator


@stats_decorate('age', 'goals')  # Add properties and related stat methods to class.
class Player:
    pass


if __name__ == '__main__':

    p1 = Player('John', 8, 1)
    p2 = Player('Tim', 9, 2)
    p3 = Player('Annie', 11, 3)
    team = Team([p1, p2, p3])

    print(f'{team.all_ages=}')
    print(f'{team.total_age=}')
    print(f'{team.average_age=:.2f}')
    print(f'{team.median_age=}')
    print()
    print(f'{team.all_goals=}')
    print(f'{team.total_goals=}')
    print(f'{team.average_goals=:.2f}')
    print(f'{team.median_goals=}')

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM