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

使用__getitem__同时支持索引与键值访问是否合理?

关于自定义度量单位类的索引访问合理性问题

我定义了一个带subunits的度量单位通用类(例如码、英尺、英寸的长度,或度、分、秒的角度),该类的属性既可以像tuple一样通过索引访问,也可以像dict一样通过键访问,同时还支持点标记访问属性(因重写__setattr__方法,属性不可修改)。相关代码如下:

class MeasureWithSubunits():
    units = ('days', 'hours', 'minutes')
    # Class variable can be assigned as normal at runtime.
    # Assigned here as an example.
    
    def __init__(self, *args) -> None:
        # Tidy up the input
        ...
        for i, unit in enumerate(self.units):
            self.__dict__[unit] = args[i] if i < len(args) else 0
    
    def __getitem__(self, index):
        if type(index) is int:
            return self.__dict__[self.units[index]]
        elif type(index) is slice:
            return [self.__dict__[self.units[i]] for i in range(
                    index.start or 0,
                    index.stop or len(self.units),
                    index.step or 1
                   )]
        else:
            return self.__dict__[index]

    def __len__(self) -> int:
        return len(self.units)

    def __setattr__(self, name, attr_value):
        raise AttributeError("Does not support attribute assignment")

我的问题是:同时允许方括号以两种近乎矛盾的方式使用是否“不妥”?尤其是键值访问方式并非必要,因为已支持点标记访问。希望依据文档解答(也欢迎有理有据的观点),或者标准库中是否有类似实现?


解答

从Python设计原则看

Python之禅(PEP 20)明确提到清晰胜于晦涩、简单胜于复杂。让__getitem__同时处理整数/切片索引和字符串键,会模糊接口的语义:用户看到obj[x]时,需要额外判断x是索引还是键,增加了理解成本,不符合清晰性原则。

标准库的参考实现

标准库中没有同时混用两种__getitem__访问方式的容器类:

  • tuple仅支持整数/切片索引,dict仅支持可哈希的键,两者的访问边界清晰;
  • collections.namedtuple作为结构化数据类,支持点标记访问和整数/切片索引,但不允许用键作为__getitem__的参数——若要按键访问,只能通过点标记或转换为dict后操作,这是在明确区分两种访问模式的职责。

你的场景分析

键值访问已经通过点标记obj.hours实现,再在__getitem__中支持字符串键属于冗余功能,反而降低了接口的直观性:

  • 习惯tuple用法的用户,遇到obj['hours']会产生困惑;
  • 点标记obj.hours的可读性本身就优于方括号键访问obj['hours']。

另外,当前实现存在潜在歧义:如果units中包含整数形式的字符串(比如units = ('1', '2')),obj[1]会触发歧义——是取索引1对应的'2',还是取键'1'对应的值?这种极端情况会引发难以排查的bug。

建议

  • 保留__getitem__的整数/切片索引功能,对齐tuple的行为,保持序列访问的清晰性;
  • 移除字符串键的访问支持,引导用户使用更直观的点标记访问属性;
  • 如果确实需要键式访问,可以单独提供get方法(如obj.get('hours')),或实现__dict__转换,但不要将两种访问模式混在__getitem__中。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 03:47:16