类属性存于cls.__dict__,实例属性存于obj.__dict__;因语义冲突(共享vs隔离)必须分离存储,否则查找、hasattr及赋值行为失效,且易引发状态不一致。

类属性和实例属性分别存在哪里?
类属性存于 cls.__dict__,实例属性存于 obj.__dict__ —— 这不是设计选择,而是内存模型决定的。Python 在创建类时,把类体中定义的变量(如 count = 0)直接写入类对象的 __dict__;而每次调用 __init__ 时,self 对象会新建一个空字典,并通过 self.xxx = value 往里塞键值对。
为什么不能共用一个字典?
因为语义冲突无法解决:
- 类属性要被所有实例共享,改一次就得全局生效;实例属性必须隔离,改
obj1.name不能影响obj2.name - 如果强行合并,查找时就无法区分“这个值是该实例独有的,还是继承自类的默认值”
-
hasattr(obj, 'attr')和'attr' in obj.__dict__的行为会失效——前者查整个链,后者只查实例层,这种分层能力依赖分离存储
常见误操作:给实例赋值同名类属性
这是最容易踩的坑:
- 写
obj.attr = 123不会修改类属性,而是往obj.__dict__新增一条'attr': 123 - 之后再读
obj.attr就命中实例字典,完全绕过类字典 - 但
OtherObj.attr还走原路,读的是类字典里的旧值 → 状态不一致 - 尤其对可变类属性(如
data = [])做obj.data.append(x),实际改的是共享列表,所有实例都看到新增项
想验证存储位置?直接看 __dict__
不用猜,打印出来就清楚:
class C:
cls_attr = "shared"
def __init__(self):
self.inst_attr = "unique"
<p>c = C()
print(c.<strong>dict</strong>) # {'inst_attr': 'unique'}
print(C.<strong>dict</strong>.get('cls_attr')) # 'shared'
print('cls_attr' in c.<strong>dict</strong>) # False
print('inst_attr' in C.<strong>dict</strong>) # False</p>
真正复杂的地方不在“怎么查”,而在“什么时候该用哪个”。比如计数器要用类属性 + 类方法更新,而缓存数据必须在 __init__ 里初始化为实例属性——否则多个实例会悄悄复用同一份字典。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











