[英]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.