You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建可根据成员类属性自动新增聚合方法的Python集合类

方案1:用__getattr__动态生成聚合属性(零维护成本,最省心)

这个方案不需要手动新增任何Team类的代码,只要Player新增property,Team会自动支持对应4种聚合属性:

from statistics import mean, median
from functools import lru_cache

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

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

    # 新增property完全不用改Team代码
    @property
    def score(self):
        return self._score

    # 提前收集所有公开的property名称,用于合法性校验
    @classmethod
    def get_properties(cls):
        return [k for k, v in vars(cls).items() if isinstance(v, property)]

class Team:
    def __init__(self, players):
        self.players = players
        self._player_properties = set(Player.get_properties())
        # 定义聚合规则:前缀 -> 计算函数
        self._agg_rules = {
            'all_': lambda values: {p.name: v for p, v in zip(self.players, values)},
            'total_': sum,
            'average_': mean,
            'median_': median
        }

    def __getattr__(self, attr_name):
        # 匹配前缀和属性名
        for prefix, agg_func in self._agg_rules.items():
            if attr_name.startswith(prefix):
                prop_name = attr_name[len(prefix):]
                # 处理单复数匹配,比如all_ages对应age,all_scores对应score
                if prop_name.endswith('s'):
                    prop_name = prop_name[:-1]
                if prop_name in self._player_properties:
                    # 提取所有玩家对应的属性值
                    values = [getattr(p, prop_name) for p in self.players]
                    return agg_func(values)
        # 没有匹配的属性走默认报错逻辑
        raise AttributeError(f"'Team' object has no attribute '{attr_name}'")

# 测试代码
p1 = Player('John', 8, 90)        
p2 = Player('Tim', 9, 85)        
p3 = Player('Annie', 11, 95)        
team = Team([p1, p2, p3])

# 原有age属性正常使用
print(team.all_ages) # {'John':8, 'Tim':9, 'Annie':11}
print(team.total_age) # 28
# 新增的score属性自动支持
print(team.all_scores) # {'John':90, 'Tim':85, 'Annie':95}
print(team.average_score) # 90

这个方案的优势是完全适配Player属性的新增/修改/删除,不需要对Team类做任何调整,适合属性频繁迭代的业务场景。如果担心重复计算性能问题,可以给__getattr__加缓存,或者在第一次计算后把属性动态绑定到实例上。


方案2:预生成property(支持IDE自动补全,对开发者更友好)

如果需要IDE能识别所有聚合属性,可以用类装饰器在定义Team类的时候自动批量生成所有property:

def generate_agg_properties(player_cls):
    agg_rules = {
        'all_': lambda self, prop: {p.name: getattr(p, prop) for p in self.players},
        'total_': lambda self, prop: sum(getattr(p, prop) for p in self.players),
        'average_': lambda self, prop: mean(getattr(p, prop) for p in self.players),
        'median_': lambda self, prop: median(getattr(p, prop) for p in self.players),
    }
    def decorator(team_cls):
        # 获取所有Player的property
        player_props = [k for k, v in vars(player_cls).items() if isinstance(v, property)]
        for prop in player_props:
            for prefix, func in agg_rules.items():
                # 生成属性名,all_前缀加复数s
                attr_name = f"{prefix}{prop}s" if prefix == 'all_' else f"{prefix}{prop}"
                # 绑定property
                setattr(team_cls, attr_name, property(lambda self, p=prop, f=func: f(self, p)))
        return team_cls
    return decorator

# 使用装饰器修饰Team类
@generate_agg_properties(Player)
class Team:
    def __init__(self, players):
        self.players = players

后续只要Player新增了property,重新加载代码后Team就会自动生成对应的聚合属性,IDE可以正常提示补全。


内容的提问来源于stack exchange,提问作者j_becker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 13:48:02