类变量和实例变量的核心区别
类变量和实例变量是 Python 面向对象编程中两种不同作用域的属性,核心差异体现在归属、作用域、内存存储、访问 / 修改方式等方面,具体如下:
一、核心区别对比
| 对比维度 | 类变量(Class Variable) | 实例变量(Instance Variable) |
|---|---|---|
| 归属 / 所有者 | 属于类本身,与实例无关 | 属于每个独立的实例,每个实例拥有专属副本 |
| 定义位置 | 类体中、所有实例方法之外(通常在类顶部) | 通常在__init__方法中(或其他实例方法中),以self.变量名定义 |
| 内存存储 | 仅在类的命名空间中存储一份,内存中唯一 | 每个实例在自身__dict__(实例命名空间)中存储一份,多实例多份副本 |
| 作用域 / 共享性 | 被该类的所有实例共享,一个修改(正确方式)会影响所有实例 | 仅作用于当前实例,不同实例的同名实例变量互不干扰 |
| 访问方式 | 类名。类变量 / 实例。类变量(优先查实例,再查类) | 仅能通过实例.实例变量访问(类名无法直接访问) |
| 修改方式 | 推荐用类名.类变量修改;通过实例需type(实例)/实例.__class__(避免创建实例变量) | 直接通过实例.实例变量 = 新值修改,仅影响当前实例 |
| 生命周期 | 随类的加载而创建,随类的销毁而消失(程序结束或类被删除) | 随实例的创建而创建,随实例被垃圾回收而销毁 |
二、具体详解与示例
1. 定义方式不同
类变量:类体中独立定义(无self)
python
运行
class Student: # 类变量:属于 Student 类,所有学生共享 class_name = "高一(1)班" # 类体中、方法外定义 student_count = 0 # 类变量:统计学生总数 def __init__(self, name, age): # 实例变量:属于每个学生实例,用 self. 定义 self.name = name # 每个学生有专属姓名 self.age = age # 每个学生有专属年龄 # 修改类变量(统计实例数量) Student.student_count += 1实例变量:__init__中用self定义
上述代码中,name和age是实例变量,每个Student实例都会独立拥有这两个属性,互不影响。
2. 归属与共享性不同
类变量:所有实例共享
类变量存储在类的命名空间中,仅一份副本,所有实例访问的都是同一个值:
python
运行
# 创建两个学生实例 stu1 = Student("张三", 16) stu2 = Student("李四", 17) # 所有实例共享类变量 print(stu1.class_name) # 输出:高一(1)班 print(stu2.class_name) # 输出:高一(1)班 print(Student.class_name) # 输出:高一(1)班 # 类变量被修改后,所有实例都受影响 Student.class_name = "高一(2)班" print(stu1.class_name) # 输出:高一(2)班 print(stu2.class_name) # 输出:高一(2)班 # 类变量统计实例数量(共享性体现) print(Student.student_count) # 输出:2(两个实例创建后,类变量累加为2)实例变量:每个实例独立拥有
不同实例的实例变量相互独立,修改一个实例的实例变量不会影响其他实例:
python
运行
# 修改 stu1 的实例变量 stu1.name = "张三三" stu1.age = 18 # stu2 的实例变量不受影响 print(stu1.name, stu1.age) # 输出:张三三 18 print(stu2.name, stu2.age) # 输出:李四 173. 访问与修改方式不同
类变量的访问与修改
- 访问:支持
类名.类变量(推荐)或实例.类变量; - 修改:必须通过类名(或
type(实例)/实例.__class__)修改,否则通过实例.类变量 = 新值会创建同名实例变量,屏蔽类变量。
python
运行
# 错误修改方式:创建实例变量,不影响类变量 stu1.class_name = "高一(3)班" print(stu1.class_name) # 输出:高一(3)班(访问实例变量) print(stu2.class_name) # 输出:高一(2)班(仍访问类变量) print(Student.class_name) # 输出:高一(2)班(类变量未变) # 正确修改方式:通过类名或实例获取类后修改 Student.class_name = "高一(4)班" # 推荐 # 或 type(stu1).class_name = "高一(4)班" # 或 stu1.__class__.class_name = "高一(4)班" print(stu1.class_name) # 输出:高一(4)班(实例无同名变量,访问类变量) print(stu2.class_name) # 输出:高一(4)班实例变量的访问与修改
- 访问:仅支持
实例.实例变量,类名无法直接访问(类没有实例变量的引用); - 修改:直接
实例.实例变量 = 新值即可,仅影响当前实例。
python
运行
# 正确访问实例变量 print(stu1.name) # 输出:张三三 # 错误:类名无法访问实例变量 # print(Student.name) # 报错:AttributeError: type object 'Student' has no attribute 'name' # 修改实例变量 stu2.age = 19 print(stu2.age) # 输出:19 print(stu1.age) # 输出:18(不受影响)4. 内存存储与生命周期不同
- 类变量:程序运行时,类被加载到内存时创建,存储在类的命名空间中,仅一份;直到程序结束或类被显式删除,类变量才会被销毁。
- 实例变量:当创建实例(
类名())时,在实例的__dict__中创建,每个实例对应一份独立存储;当实例不再被引用(如赋值为None),被垃圾回收机制回收时,实例变量随之销毁。
python
运行
# 查看类的命名空间(包含类变量) print(Student.__dict__) # 可看到 class_name、student_count 等类变量 # 查看实例的命名空间(包含实例变量,无同名类变量) print(stu1.__dict__) # 输出:{'name': '张三三', 'age': 18}(无 class_name)三、总结
- 类变量归属于类,仅一份副本,所有实例共享;实例变量归属于单个实例,多实例多份副本,互不干扰。
- 类变量定义在类体方法外,实例变量通常在
__init__中用self定义。 - 类变量推荐用
类名.类变量访问 / 修改;实例变量仅能通过实例.实例变量操作。 - 类变量生命周期随类,实例变量生命周期随实例;内存中类变量仅存储一份,实例变量每个实例各存一份。
https://avg.163.com/topic/detail/8254755
https://avg.163.com/topic/detail/8254763
https://avg.163.com/topic/detail/8254780
https://avg.163.com/topic/detail/8254753
https://avg.163.com/topic/detail/8254756
https://avg.163.com/topic/detail/8254760
https://avg.163.com/topic/detail/8254765
https://avg.163.com/topic/detail/8254775
https://avg.163.com/topic/detail/8254782
https://avg.163.com/topic/detail/8254754
https://avg.163.com/topic/detail/8254795
https://avg.163.com/topic/detail/8254789
https://avg.163.com/topic/detail/8254794
https://avg.163.com/topic/detail/8254761
https://avg.163.com/topic/detail/8254752
https://avg.163.com/topic/detail/8254805
https://avg.163.com/topic/detail/8254779
https://avg.163.com/topic/detail/8254767
https://avg.163.com/topic/detail/8254808
https://avg.163.com/topic/detail/8254801
https://avg.163.com/topic/detail/8254792
https://avg.163.com/topic/detail/8254778
https://avg.163.com/topic/detail/8254802
https://avg.163.com/topic/detail/8254751
https://avg.163.com/topic/detail/8254750
https://avg.163.com/topic/detail/8254749
https://avg.163.com/topic/detail/8254764
https://avg.163.com/topic/detail/8254790
https://avg.163.com/topic/detail/8254766
https://avg.163.com/topic/detail/8254762
https://avg.163.com/topic/detail/8254776
https://avg.163.com/topic/detail/8254777
https://avg.163.com/topic/detail/8254791
https://avg.163.com/topic/detail/8254793
https://avg.163.com/topic/detail/8254809
https://avg.163.com/topic/detail/8254804
https://avg.163.com/topic/detail/8254757
https://avg.163.com/topic/detail/8254774
https://avg.163.com/topic/detail/8254768
https://avg.163.com/topic/detail/8254787
https://avg.163.com/topic/detail/8254781
https://avg.163.com/topic/detail/8254806
https://avg.163.com/topic/detail/8254759
https://avg.163.com/topic/detail/8254796
https://avg.163.com/topic/detail/8254773
https://avg.163.com/topic/detail/8254807
https://avg.163.com/topic/detail/8254788
https://avg.163.com/topic/detail/8254803