类变量和实例变量的作用域分别是什么?

类变量 & 实例变量 作用域完整区分

一、先理清两个核心概念

  1. 作用域 = 能访问到该变量的代码范围
  2. 两者载体不同:
    • 类变量挂载在
    • 实例变量挂载在单个实例 self

二、实例变量(self.xxx)作用域

1. 可访问范围

  1. 当前实例内部所有方法(实例方法、类方法不行、静态方法无 self)

    python

    运行

    class A: def __init__(self): self.name = "张三" # 实例变量 def test(self): print(self.name) # ✅ 实例方法内可访问
  2. 外部代码:通过实例对象访问

    python

    运行

    a = A() print(a.name) # ✅ 外部通过实例读取

2. 不可访问范围

  1. 类方法@classmethod中,只用cls拿不到实例变量;
  2. 静态方法@staticmethod无 self、无 cls,完全无法访问;
  3. 直接用类名A.name访问,报错;
  4. 其他实例不能访问另一个实例的实例变量:

    python

    运行

    a1 = A() a2 = A() print(a1.name) print(a2.name) # a2 不能读取 a1 的 self.name,各自独立

3. 生命周期绑定作用域

实例销毁后,实例变量作用域直接消失,全局、其他类都拿不到。

三、类变量(类内直接定义,self 外)作用域

1. 可访问范围

  1. 类内部任意位置
    • 实例方法:self.类变量名/类名.类变量名
    • 类方法:cls.类变量名
    • 静态方法:类名.类变量名
  2. 外部代码两种访问方式

    python

    运行

    class A: count = 0 # 方式1(推荐) print(A.count) # 方式2(仅读取,赋值会踩坑) a = A() print(a.count)
  3. 子类可继承访问

    python

    运行

    class B(A): pass print(B.count) # 子类能读取父类类变量

2. 不可访问范围

  • 不存在实例隔离:所有实例读取的是同一个类变量;
  • 只有删除类本身,类变量才彻底失效。

四、作用域关键区别对照表

表格

对比项实例变量 self.xxx类变量
归属载体单个实例对象类本身,所有实例共享
实例方法内✅ self.xxx 直接访问✅ self.var/ 类名.var
类方法内❌ 无法访问(无 self)✅ cls.var
静态方法内❌ 无法访问✅ 类名.var
类名直接访问❌ 报错✅ 推荐访问方式
跨实例访问❌ A 实例不能读 B 实例变量✅ 全部实例共用同一份
子类继承❌ 不继承实例变量✅ 子类可读取父类类变量
外部通过实例赋值正常修改自身变量❌ 不会改类变量,新建同名实例变量遮蔽

五、补充边界案例

1. 实例方法读取类变量没问题,但赋值有坑

python

运行

class A: num = 10 def func(self): print(self.num) # 读取:先找实例无,向上找类变量 ✅ self.num = 20 # 赋值:新增实例变量,不再操作类变量

2. 类方法只能操作类变量,碰不到实例变量

python

运行

class A: num = 10 def __init__(self): self.age = 18 @classmethod def cls_func(cls): print(cls.num) # ✅ print(cls.age) # ❌ 报错,类看不到实例变量

3. 子类修改类变量,不会污染父类作用域

python

运行

class Parent: val = 1 class Son(Parent): pass Son.val = 99 print(Parent.val) # 1,父类作用域不受影响

六、一句话总结

  1. 实例变量作用域只局限于单个实例,只有拿到该实例对象才能访问,实例之间完全隔离;
  2. 类变量作用域覆盖整个类、所有实例、子类、全局代码,只要类存在,任何地方都能通过类名读取修改。