如何为Python Dataclass实现无魔法数的__len__方法?
问题
我有一个用于计时器集合的dataclass,该类的每个实例可拥有不同数量的计时器,单个实例的计时器数量固定但实例间存在差异。我希望通过__len__方法获取特定实例的计时器数量,但不想使用示例代码中的魔法数,而是希望调用__len__时自动计算,避免维护错误。以下是我的代码:
from dataclasses import dataclass # 假设tmr是已导入的计时器模块 import tmr @dataclass class SSTimers(): def tic(self): pass def __iter__(self): return iter([]) @dataclass class Timers(SSTimers): intervalTimer = tmr.Timer(0) vSafetyPTimer = tmr.Timer(0) aRefractoryTimer = tmr.Timer(0) aBlankingTimer = tmr.Timer(0) vRefractoryTimer = tmr.Timer(0) vBlankingTimer = tmr.Timer(0) def tic(self): self.intervalTimer.tic() self.vSafetyPTimer.tic() self.aRefractoryTimer.tic() self.aBlankingTimer.tic() self.vRefractoryTimer.tic() self.vBlankingTimer.tic() def __len__(self): return 6 def __iter__(self): return iter([self.intervalTimer, self.vSafetyPTimer, self.aRefractoryTimer, self.aBlankingTimer, self.vRefractoryTimer, self.vBlankingTimer ])
我希望len()能返回类似len(__iter__)的结果。
解决方案
方法1:复用__iter__结果计算长度
直接在__len__里调用自身的__iter__方法,转成列表后取长度,这样只要__iter__的列表维护正确,__len__就自动同步数量:
def __len__(self): return len(list(self.__iter__()))
缺点是每次调用len()都会生成新列表,性能敏感场景需要优化。
方法2:预存计时器列表(推荐)
提前把所有计时器整理成一个列表属性,同时给tic()、__len__、__iter__复用,大幅减少重复代码和维护成本:
@dataclass class Timers(SSTimers): intervalTimer = tmr.Timer(0) vSafetyPTimer = tmr.Timer(0) aRefractoryTimer = tmr.Timer(0) aBlankingTimer = tmr.Timer(0) vRefractoryTimer = tmr.Timer(0) vBlankingTimer = tmr.Timer(0) def __post_init__(self): self._timers = [ self.intervalTimer, self.vSafetyPTimer, self.aRefractoryTimer, self.aBlankingTimer, self.vRefractoryTimer, self.vBlankingTimer ] def tic(self): for timer in self._timers: timer.tic() def __len__(self): return len(self._timers) def __iter__(self): return iter(self._timers)
新增或删除计时器时,只需要修改_timers列表和对应的类属性即可,tic()、__len__、__iter__都会自动适配,完全避免魔法数和重复维护。
方法3:自动识别计时器属性
如果不想手动维护列表,可以通过属性类型过滤,自动统计所有tmr.Timer类型的公共属性:
def __len__(self): return sum( 1 for attr_name in dir(self) if not attr_name.startswith('_') and isinstance(getattr(self, attr_name), tmr.Timer) )
注意要排除以_开头的内部属性,否则会误统计。适合类中公共属性全是计时器的场景。
内容的提问来源于stack exchange,提问作者JKomp
相关产品推荐
相关产品推荐

