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

如何为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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 12:55:55