属性访问基础回顾
- 直接访问:对象.属性(如 c.x)
- BIF 访问方式
- getattr(obj, name[, default]):获取属性,无则返回默认值
- setattr(obj, name, value):设置属性
- delattr(obj, name):删除属性
- property 函数:绑定属性的获取、设置、删除方法
- 用法:property(get方法, set方法, del方法)
- 效果:通过属性名间接操作对应方法
核心属性访问魔法方法
- getattr(self, name)
- 触发时机:访问不存在的属性时
- 作用:自定义不存在属性的访问逻辑
- getattribute(self, name)
- 触发时机:任何属性被访问时(优先级最高)
- 注意:需通过 super() 调用基类方法,避免死循环
- setattr(self, name, value)
- 触发时机:设置任何属性时(包括初始化赋值)
- 作用:自定义属性赋值逻辑
- delattr(self, name)
- 触发时机:删除任何属性时
- 作用:自定义属性删除逻辑
魔法方法执行顺序
- 访问属性 → 先触发 getattribute
- 若属性不存在 → 再触发 getattr
- 设置属性 → 触发 setattr
- 删除属性 → 触发 delattr
重点陷阱:无限递归
- 场景:在 setattr 内直接给 self.属性赋值
- 示例:矩形类重写 setattr 时,self.width = value 会再次触发 setattr
- 解决方案
- 调用基类方法:super().setattr(name, value)
- 操作 dict 属性:self.dict[name] = value
实战案例:矩形类(支持正方形属性)
- 需求:赋值 square 属性时,同步设置 width 和 height 为边长
- 实现步骤
- init 初始化 width 和 height
- 重写 setattr:判断 name 为 square 时,同步赋值宽高
- 用 super() 或 dict 避免递归
- 新增 get_area 方法计算面积