如何合理处理拥有大量属性的类?
朋友,遇到这种属性超多的类确实头大,不过你这个场景其实挺典型的——体育比赛数据本来就是成对的主场/客场统计,咱们可以从结构优化和代码简化两个方向来解决问题,具体给你几个实用方案:
一、按逻辑分组封装属性
把主场和客场的统计数据单独抽成一个子结构,比如一个TeamStats类,这样原有的Statistics类只需要维护match_id、home_stats、away_stats三个核心属性就行。不仅代码结构更清晰,后续维护分组统计字段也更方便,不管是存数据库还是做数学模型计算,都能很直观地拿到某一队的完整数据。
示例代码:
class TeamStats: def __init__(self, ball_possession=None, goal_attempts=None, shots_on_goal=None, shots_off_goal=None, blocked_shots=None, free_kicks=None, corner_kicks=None, offsides=None, throw_ins=None, goalkeeper_saves=None, fouls=None, red_cards=None, yellow_cards=None, total_passes=None, completed_passes=None, tackles=None, attacks=None, dangerous_attacks=None): self.ball_possession = ball_possession self.goal_attempts = goal_attempts self.shots_on_goal = shots_on_goal # 其他属性依次赋值...(可结合下面的dataclass进一步简化) class Statistics: def __init__(self, match_id, home_stats=None, away_stats=None): self.match_id = match_id # 为空时自动初始化空的TeamStats,避免后续访问报错 self.home_stats = home_stats or TeamStats() self.away_stats = away_stats or TeamStats()
之后访问属性就变成了stats.home_stats.ball_possession,比原来的长名字更规整,也不容易搞混主场客场的字段。
二、用数据类简化冗余代码
如果你用的是Python 3.7+,强烈推荐用dataclasses来替代手动写__init__方法,它能自动帮你生成属性赋值、__repr__、__eq__等通用方法,代码量能减少一大半,同时还保留类属性的清晰访问优势。
示例代码:
from dataclasses import dataclass @dataclass class TeamStats: ball_possession: float | None = None goal_attempts: int | None = None shots_on_goal: int | None = None shots_off_goal: int | None = None blocked_shots: int | None = None free_kicks: int | None = None corner_kicks: int | None = None offsides: int | None = None throw_ins: int | None = None goalkeeper_saves: int | None = None fouls: int | None = None red_cards: int | None = None yellow_cards: int | None = None total_passes: int | None = None completed_passes: int | None = None tackles: int | None = None attacks: int | None = None dangerous_attacks: int | None = None @dataclass class Statistics: match_id: int home_stats: TeamStats | None = None away_stats: TeamStats | None = None
这样写出来的代码简洁干净,还自带类型提示,IDE能自动补全属性名,不管是写数据库操作还是数学模型计算,都能减少拼写错误,调试也更方便。
三、如果不想改结构,优化初始化逻辑
要是你暂时不想调整类的结构,也可以通过循环来简化__init__里大量重复的赋值代码,避免手动写几十行self.xxx = xxx。
示例代码:
class Statistics: # 把所有单队的统计字段存成列表 _TEAM_STAT_FIELDS = [ 'ball_possession', 'goal_attempts', 'shots_on_goal', 'shots_off_goal', 'blocked_shots', 'free_kicks', 'corner_kicks', 'offsides', 'throw_ins', 'goalkeeper_saves', 'fouls', 'red_cards', 'yellow_cards', 'total_passes', 'completed_passes', 'tackles', 'attacks', 'dangerous_attacks' ] def __init__(self, match_id, **kwargs): self.match_id = match_id # 循环处理主场属性 for field in self._TEAM_STAT_FIELDS: setattr(self, f'home_{field}', kwargs.get(f'home_{field}')) # 循环处理客场属性 for field in self._TEAM_STAT_FIELDS: setattr(self, f'away_{field}', kwargs.get(f'away_{field}'))
以后要是需要新增统计字段,只需要在_TEAM_STAT_FIELDS里加个名字就行,不用再重复写两遍赋值代码,维护起来省心很多。
最后聊聊你纠结的字典vs类的问题
字典虽然灵活,但类的优势在你的场景里太明显了:
- 类型提示与代码补全:IDE能自动提示属性名,减少拼写错误,写代码效率更高;
- 结构清晰:类的结构是固定的,能明确知道有哪些字段,不像字典可能出现键名混乱的情况;
- 可扩展性:以后要加属性校验、自定义方法(比如计算主场客场的差值),类的方式比字典方便太多。
所以完全不用放弃类的优势,通过上面的优化方案就能解决属性过多的问题。
备注:内容来源于stack exchange,提问作者Kajander

