Python中self[name]与self.__dict__[name]的区别及AttrDict点语法解析
AttrDict代码相关问题解答
一、self.name 与 self.__dict__[name] 的区别
self.name:标准属性访问语法- 这是Python访问实例属性的常规方式,会触发完整的属性查找流程:先检查实例自身的
__dict__字典;若找不到,会依次查找类的__dict__、父类的__dict__;如果最终都找不到,还会调用重写的__getattr__方法(如果存在)。 - 在这个
AttrDict类中,当用self.name访问时,若name不在实例__dict__里,就会触发__getattr__,进而去字典的键中查找对应值。
- 这是Python访问实例属性的常规方式,会触发完整的属性查找流程:先检查实例自身的
self.__dict__[name]:直接操作属性字典- 这是跳过属性查找流程,直接访问实例的
__dict__字典(实例的所有自定义属性都存在这个字典里)。它不会触发__getattr__,也不会去类或父类的属性中查找,只针对实例自身的__dict__字典操作。 - 比如代码中
__init__方法里用self.__dict__[AttrDict.IMMUTABLE] = False,就是直接把__immutable__键值对存入实例的__dict__,避免触发属性拦截逻辑,确保这个状态标识能被正确设置和读取。
- 这是跳过属性查找流程,直接访问实例的
二、为何test.x = 100可以用点语法设置属性?
Python中,用点语法设置属性(obj.attr = value)会自动触发实例的__setattr__方法。这个AttrDict类重写了__setattr__,修改了默认的属性设置逻辑:
- 执行
test.x = 100时,会调用__setattr__('x', 100); - 方法内先判断实例是否可修改,再检查
x是否在实例的__dict__中:如果不在,就执行self[name] = value,也就是把x作为字典的键、100作为对应的值存入字典; - 普通
dict类没有重写__setattr__,默认逻辑是把属性存入实例的__dict__而非字典键值对,所以普通dict不能用点语法设置键,但AttrDict通过重写__setattr__把点语法和字典键值对操作绑定在了一起。
附原代码
class AttrDict(dict): IMMUTABLE = '__immutable__' def __init__(self, *args, **kwargs): super(AttrDict, self).__init__(*args, **kwargs) self.__dict__[AttrDict.IMMUTABLE] = False def __getattr__(self, name): if name in self.__dict__: return self.__dict__[name] elif name in self: return self[name] else: raise AttributeError(name) def __setattr__(self, name, value): if not self.__dict__[AttrDict.IMMUTABLE]: if name in self.__dict__: self.__dict__[name] = value else: self[name] = value else: raise AttributeError( 'Attempted to set "{}" to "{}", but AttrDict is immutable'. format(name, value) )
内容的提问来源于stack exchange,提问作者HeII0W0rId
相关产品推荐
相关产品推荐

