classname.attr 仍可访问原始类属性值,因实例属性仅遮蔽 self.attr;getattr(class, 'attr') 更通用,避免硬编码类名;删除实例属性非推荐做法,应明确区分实例值与类默认值。

类属性被实例属性遮蔽时,ClassName.attr 依然有效
类属性被同名实例属性“遮蔽”后,self.attr 会返回实例值,但类本身没变——直接用 ClassName.attr 仍能拿到原始类属性值。这是最直接、最安全的绕过方式,不需要反射或删除操作。
常见错误现象:obj.x = 42 后再访问 obj.x 得到 42,误以为类属性 X.x 也被改了;其实 X.x 还是原来的值,只是被实例上的 x 拦截了。
- 适用场景:只读取类属性原始值(比如默认配置、枚举常量、版本号)
- 不适用于需要动态同步类/实例状态的逻辑(那说明设计上该用
@property或描述符) - 注意大小写和拼写:写成
MyClass.Attr而非myclass.attr,否则触发NameError
用 getattr(MyClass, 'attr') 替代硬编码类名访问
当类名不确定(比如函数参数传入类对象)、或需批量处理多个类时,硬写 ClassName.attr 不灵活。getattr 是更通用的方案,且能配合 hasattr 做存在性判断。
示例:
class Config:
timeout = 30
<p>obj = Config()
obj.timeout = 5 # 遮蔽发生</p><h1>安全读取类级 timeout</h1><p>print(getattr(Config, 'timeout')) # 30
print(getattr(type(obj), 'timeout')) # 30,type(obj) 等价于 Config
</p>
-
getattr(cls, name)不会触发实例查找链,跳过实例字典 - 若属性不存在,
getattr默认抛AttributeError,可加第三个参数设默认值 - 避免用
obj.__class__.attr——虽然等价,但__class__是特殊属性,语义不如type(obj)清晰
为什么不用 del obj.attr 来“恢复”类属性访问?
删掉实例属性后,obj.attr 确实会重新落到类属性上,但这属于副作用式修复,容易引发隐蔽问题。
- 如果其他代码依赖该实例属性存在(比如
if hasattr(obj, 'attr'):),删除后逻辑可能断裂 - 多线程下
del和后续访问之间存在竞态窗口 - 类属性可能是可变对象(如
list或dict),删实例属性并不影响其内容,但会让开发者误判数据归属 - 真正需要“恢复”的场景极少;绝大多数情况只需明确区分“实例值”和“类默认值”
检查遮蔽关系:用 obj.__dict__.get('attr') 和 hasattr(type(obj), 'attr')
调试时快速确认是否发生了遮蔽,比猜更可靠。实例属性优先存在于 __dict__,类属性则需查类及其 MRO。
-
obj.__dict__.get('x')返回实例值(或None),不触发任何__getattribute__逻辑 -
hasattr(type(obj), 'x')判断类是否有该属性(含继承),比'x' in type(obj).__dict__更准确(后者不查父类) - 注意:
obj.__dict__不包含通过__slots__定义的属性,此时要用getattr(obj, 'x', None)配合hasattr组合判断
类属性和实例属性共用名字不是 bug,是 Python 的正常机制;关键在访问意图是否清晰。直接通过类名或 getattr 访问,是最轻量、最不易出错的方式。别试图“取消遮蔽”,而是让读取路径和业务语义对齐。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











