news 2026/3/24 13:56:34

类变量和实例变量的内存分配有什么不同?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
类变量和实例变量的内存分配有什么不同?

你想了解 Python 类变量和实例变量在内存分配上的本质差异,核心体现在分配时机、存储位置、内存份数、生命周期四个关键维度,下面结合原理说明和代码验证,详细拆解两者的不同:

一、核心内存分配差异对比

内存分配维度类变量实例变量
分配时机加载 / 定义时(程序运行到类定义代码时)实例创建时(调用类构造器类名()时)
存储位置类对象的命名空间(类的内存区域)实例对象的独立命名空间(每个实例的内存区域)
内存份数仅分配1 份内存,全局唯一每个实例分配独立 1 份内存,实例数量 = 内存份数
生命周期随类的销毁而销毁(程序结束 / 类被删除)随实例的销毁而销毁(实例被垃圾回收时)
访问映射实例访问类变量时,是「查找类的命名空间」,而非实例自身存储实例访问自身变量时,直接查找自身命名空间

二、逐维度详细解释 + 代码验证

1. 分配时机:类加载时分配类变量,实例创建时分配实例变量
  • 类变量:程序运行到class 类名:代码块时,Python 会创建类对象并为类变量分配内存,无需创建实例即可存在。
  • 实例变量:只有当调用类名()创建实例时,Python 才会为该实例分配内存,并在__init__方法中初始化实例变量,类加载阶段不存在实例变量。

python

运行

# 验证:类加载时,类变量已存在,实例变量尚未分配 class Student: # 类加载时,class_var 已分配内存 class_var = "类变量内存已分配" def __init__(self, name): # 只有创建实例时,name 才会被分配内存 self.name = name # 无需创建实例,可直接访问类变量(证明类变量已分配内存) print(Student.class_var) # 输出:类变量内存已分配 # 此时无实例,实例变量不存在(无法访问) # print(Student.name) # 报错:AttributeError,实例变量未分配 # 创建实例后,实例变量才分配内存 stu1 = Student("张三") print(stu1.name) # 输出:张三(实例变量内存已分配)
2. 存储位置:类变量存在类命名空间,实例变量存在实例命名空间

Python 中,类和实例都有专属的__dict__属性(字典结构),用于存储自身的属性(变量),通过打印__dict__可直观看到两者的存储位置差异:

  • 类变量:存储在类名.__dict__中,属于类的命名空间。
  • 实例变量:存储在实例名.__dict__中,属于实例的独立命名空间,实例的__dict__中不会存储类变量(仅在访问时回溯到类的命名空间)。

python

运行

class Student: class_var = "北京大学" # 类变量:存在类的 __dict__ def __init__(self, name, score): self.name = name # 实例变量:存在实例的 __dict__ self.score = score # 实例变量:存在实例的 __dict__ # 查看类的命名空间:包含类变量 print("类的命名空间:", Student.__dict__) # 输出(关键部分):{'class_var': '北京大学', ...} # 创建两个实例 stu1 = Student("张三", 90) stu2 = Student("李四", 85) # 查看实例1的命名空间:仅包含自身的实例变量,无类变量 print("stu1 的命名空间:", stu1.__dict__) # 输出:{'name': '张三', 'score': 90} # 查看实例2的命名空间:独立于stu1,仅包含自身实例变量 print("stu2 的命名空间:", stu2.__dict__) # 输出:{'name': '李四', 'score': 85} # 实例访问类变量时,是回溯到类的命名空间查找,而非自身存储 print(stu1.class_var) # 本质是查找 Student.__dict__['class_var']
3. 内存份数:类变量仅 1 份内存,实例变量多份独立内存
  • 类变量:全局只有 1 份内存地址,所有实例共享这一份数据,修改类变量(通过类名)会影响所有实例。
  • 实例变量:每个实例对应独立的内存地址,实例之间的变量互不干扰,修改一个实例的变量不会影响其他实例。

python

运行

class Student: class_var = 0 # 仅1份内存 def __init__(self, name): self.name = name # 每个实例独立内存 # 验证类变量的内存地址(所有引用指向同一内存) stu1 = Student("张三") stu2 = Student("李四") # 类、stu1、stu2 访问的 class_var 是同一内存地址 print(id(Student.class_var)) # 输出:xxx(唯一内存地址) print(id(stu1.class_var)) # 输出:xxx(与上面地址相同) print(id(stu2.class_var)) # 输出:xxx(与上面地址相同) # 验证实例变量的内存地址(每个实例独立) print(id(stu1.name)) # 输出:yyy(独立内存地址) print(id(stu2.name)) # 输出:zzz(与上面地址不同) # 修改类变量(1份内存),所有实例同步变化 Student.class_var = 100 print(stu1.class_var, stu2.class_var) # 输出:100 100 # 修改实例变量(独立内存),互不影响 stu1.name = "张小三" print(stu1.name, stu2.name) # 输出:张小三 李四
4. 生命周期:类变量随类销毁,实例变量随实例销毁
  • 类变量:类在程序运行期间始终存在,只有当程序结束(或通过del显式删除类)时,类对象被销毁,类变量的内存才会被回收。
  • 实例变量:实例被创建后存在,当实例不再被引用(如变量赋值为None、超出作用域),Python 垃圾回收机制会销毁该实例,实例变量的内存也会随之被回收。

python

运行

class Student: class_var = "生命周期随类" def __init__(self, name): self.name = name # 生命周期随实例 # 1. 类变量始终存在(程序运行中) print(Student.class_var) # 正常访问 # 2. 创建实例,实例变量分配内存 stu = Student("张三") print(stu.name) # 正常访问 # 3. 销毁实例(解除引用,触发垃圾回收) stu = None # 实例无引用,会被垃圾回收,实例变量内存释放 # print(stu.name) # 报错:NameError(实例已销毁) # 4. 类变量仍存在(类未销毁) print(Student.class_var) # 仍能正常输出:生命周期随类 # 5. 显式删除类,类变量内存释放 del Student # print(Student.class_var) # 报错:NameError(类已销毁,类变量不存在)

三、特殊场景:可变类型类变量的内存特性(补充)

对于列表、字典等可变类型类变量,其「内存地址(引用)」仅 1 份(符合类变量内存特性),但实例可以修改其内部元素(无需重新赋值),本质是操作同一份内存中的可变对象,因此会影响所有实例:

python

运行

class Group: # 可变类型类变量:仅1份内存(存储列表的引用) members = [] def add_member(self, name): # 操作同一份内存中的列表元素,所有实例共享变化 self.members.append(name) g1 = Group() g2 = Group() g1.add_member("张三") # 两者访问的是同一份内存中的列表 print(g1.members) # 输出:['张三'] print(g2.members) # 输出:['张三'] print(id(g1.members) == id(g2.members)) # 输出:True(同一内存地址)

四、总结

  1. 类变量:类加载时分配 1 份内存,存在类命名空间,生命周期随类,所有实例共享同一份内存数据;
  2. 实例变量:实例创建时分配独立内存,存在各自实例命名空间,生命周期随实例,实例间内存互不干扰;
  3. 实例访问类变量是「回溯查找类命名空间」,并非实例自身存储了类变量;
  4. 可变类型类变量的「引用内存」仅 1 份,修改内部元素会影响所有实例,本质是操作同一可变对象。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/21 0:35:34

如何快速恢复ZIP加密文件:bkcrack完整使用指南

忘记ZIP文件密码是很多人都会遇到的烦恼,特别是那些存放重要数据的加密压缩包。bkcrack工具采用先进的已知明文分析技术,让您无需密码即可直接访问被加密的文件内容。这款免费开源工具基于密码学研究成果,专门针对传统PKWARE加密方案&#xf…

作者头像 李华
网站建设 2026/3/15 13:43:56

Dify镜像集成Vault管理密钥与凭证

Dify镜像集成Vault管理密钥与凭证 在AI应用快速从实验原型走向生产部署的今天,一个看似不起眼却频频引发安全事件的问题浮出水面:API密钥去哪儿了? 你可能已经用Dify搭建了一个功能完整的智能客服Agent,也配置好了RAG知识库&#…

作者头像 李华
网站建设 2026/3/24 13:07:45

【收藏必备】Context Engineering:LLM OS时代的软件工程实践指南

几年前,当 Prompt Engineering 概念被提出来的时候,有个流行的观点:Prompt Engineering 不会存在很长时间,会随着 LLM 能力强大逐渐弱化。类比于搜索引擎刚出来的时候,有很多复杂的搜索技巧,比如使用星号作…

作者头像 李华
网站建设 2026/3/15 18:40:51

想玩转AutoGLM?先看看你是否属于这6类高潜力目标用户

第一章:Open-AutoGLM主要用户群体Open-AutoGLM 作为一款开源的自动化通用语言模型工具,吸引了多个技术背景和应用场景下的用户群体。其灵活性与可扩展性使其在科研、企业开发和个人开发者中均获得了广泛青睐。科研人员与学术机构 科研团队利用 Open-Auto…

作者头像 李华
网站建设 2026/3/15 17:41:17

jscope配合STM32实现高速采样完整示例

用 jscope 搭上 STM32,把变量变成“示波器波形”——高速采样调试实战全记录你有没有过这样的经历:在调一个 PID 控制环时,error、output这些关键变量到底怎么变化的?想看一眼,只能靠printf打出来,再复制到…

作者头像 李华
网站建设 2026/3/21 4:52:31

Open-AutoGLM框架实战指南:5步实现企业级AI自动化部署

第一章:Open-AutoGLM框架实战指南:5步实现企业级AI自动化部署在企业级AI系统部署中,Open-AutoGLM框架通过模块化设计与自动化流水线能力,显著提升了模型集成与服务发布的效率。该框架支持从数据预处理、模型微调到API封装的一体化…

作者头像 李华