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