Python类__getitem__、__setitem__的用途及与get/set装饰器的差异
Python __getitem__与__setitem__方法相关问题解答
1. getitem、__setitem__的额外用途及与property装饰器的差异
自定义类中除语法访问外的其他用途
- 实现类的迭代能力:只要自定义类实现了
__getitem__,实例就可以直接被for循环遍历,也支持iter()、next()等迭代操作,甚至不需要额外实现__iter__方法;同时in关键字判断成员存在性时也会默认调用__getitem__遍历匹配。 - 对齐标准容器的使用体验:自定义映射/序列类型时,通过这两个方法可以让类实例获得和原生字典、列表完全一致的方括号操作逻辑,降低使用者的学习成本,常见于自定义ORM模型、配置管理类等场景。
- 兼容通用工具逻辑:大量Python内置及第三方工具函数默认对支持方括号访问的对象做读写操作,自定义类实现这两个方法后可以直接接入这类工具,无需修改工具源码。
与get/set装饰器(property)的差异
- 作用对象不同:
__getitem__/__setitem__面向运行时传入的动态键/索引,支持处理任意数量、任意命名的键值,不需要提前声明。- property装饰器(即你说的get、set装饰器)面向预定义的固定属性,每个属性都需要单独编写对应的get/set方法,只能处理提前明确的属性名。
- 调用逻辑不同:
- 仅当使用方括号语法
obj[key]访问时才会触发这两个dunder方法,读写逻辑完全由自定义实现决定,和实例自身的属性没有强制关联。 - 仅当使用点语法
obj.attr访问预定义的property属性时才会触发装饰器对应的方法,未预定义的属性会走默认的属性查找逻辑,和property无关。
- 仅当使用方括号语法
2. 类与实例的同名属性访问规则
点语法访问属性时遵循「从下到上」的就近查找规则,优先级如下:
- 优先查找实例自身的
__dict__属性,实例自身绑定的属性优先级最高,测试代码中d.newkey返回?就是因为实例自身有newkey属性,覆盖了类属性。 - 实例自身没有对应属性时,会查找实例所属类的
__dict__,也就是类属性,测试代码中ADict.newkey返回!就是直接访问类层级的属性。 - 类层级也没有对应属性时,会按照类的方法解析顺序(MRO)向父类逐层查找。
- 所有层级都找不到对应属性时,抛出
AttributeError。
注意:上述规则仅适用于点语法
obj.attr访问,方括号obj[key]的访问逻辑完全由自定义的__getitem__实现决定,和这套属性查找规则无关。
测试代码最后一行报错原因
print(d.oldkey)走的是点语法属性查找逻辑:
- 实例d的
__dict__中只有data、newkey两个属性,不存在oldkey。 - 类ADict的
__dict__中也没有oldkey属性,父类也没有对应定义,因此抛出AttributeError。
你之前执行的d['oldkey'] = 'notnew'触发的是自定义的__setitem__方法,只是将键值对存入了实例内部的self.data字典中,没有将oldkey绑定为实例的属性,因此只能通过d['oldkey']访问到对应值,无法通过点语法访问。
内容的提问来源于stack exchange,提问作者Tim Pozza
相关产品推荐
相关产品推荐

