17370845950

类属性和实例属性同名时读取顺序及修改行为详解
当类属性和实例属性同名时,读取优先实例属性

,修改默认操作实例属性;del删除仅影响当前作用域,误用可变类属性会导致实例间共享。

当类属性和实例属性同名时,Python 的读取和修改行为遵循明确的规则:读取时优先使用实例属性(如果存在),修改时默认操作的是实例属性(不会影响类属性),除非显式通过类名操作。

读取时:实例属性覆盖类属性

访问对象属性时,Python 先在实例的 __dict__ 中查找,命中则直接返回;未命中才去类及其父类的 __dict__ 中查找。因此,一旦实例拥有同名属性,类属性就被“遮蔽”(shadowed)。

  • 例如:class A: x = 10; a = A(); a.x = 20a.x 读取结果为 20(来自实例)
  • A.x 仍是 10,不受影响
  • 新创建的实例(如 b = A())未设置 xb.x 读取的是类属性 10

修改时:默认创建或更新实例属性

对实例执行赋值操作(如 obj.attr = value),Python 总是将该属性写入实例的 __dict__,无论类中是否已存在同名类属性。

  • a.x = 30 并不会改变 A.x,只是更新了 a.__dict__['x']
  • 若想修改类属性本身,必须显式通过类名赋值:A.x = 30
  • 注意:修改类属性会影响所有尚未覆盖该属性的实例(即其 __dict__ 中无该键的实例)

删除行为:只影响当前作用域

使用 del obj.attr 删除的是实例属性;删除后再次访问该属性,会自动回退到类属性(如果存在)。

  • del a.x 后,a.x 又变为 A.x 的值(如 10)
  • del A.x 则从类中移除该属性,之后所有未定义 x 的实例访问 x 都会触发 AttributeError
  • 不能用 del obj.attr 删除类属性——它只作用于实例字典

常见误区与建议

容易误以为给实例赋同名属性是在“修改类属性”,或误用 self.attr = ... 初始化可变类属性(如列表、字典),导致多个实例意外共享同一对象。

  • ❌ 错误模式:class B: data = []; def add(self, x): self.data.append(x) → 所有实例共用一个 list
  • ✅ 正确做法:在 __init__ 中为每个实例创建独立副本:self.data = []
  • ✅ 检查归属:打印 obj.__dict__type(obj).__dict__ 可直观分辨属性所在位置