当前位置: 首页 > news >正文

【第三章】变量也疯狂:深入剖析 Python 数据类型与内存原理

Python 中的一切皆对象,但变量真的“存储”数据吗?为什么 a = 10 改成 a = 20 后,内存地址会变?本文将带你从基础到底层,彻底搞懂 Python 变量、数据类型与内存管理的秘密!


目录

  • 前言
  • 变量是什么?
  • Python 的数据类型
    • 数字类型
    • 字符串类型
    • 布尔类型
    • 列表、元组、字典、集合
  • 变量与内存
    • id() 函数与内存地址
    • 可变对象与不可变对象
    • 引用计数与垃圾回收
  • 小整数缓存与字符串驻留
  • is 与 == 的区别
  • 深拷贝与浅拷贝
  • 内存优化技巧
  • 实战示例
  • 总结
  • 免责声明

前言

Python 虽然是高级语言,但理解它的变量与内存模型是写出高效、可控代码的基础。很多初学者会被以下问题困扰:

  • 为什么 a = 10b = 10id 相同?
  • 为什么列表可以被原地修改,而整数不行?
  • Python 的垃圾回收机制到底怎么工作?
  • 为什么 is== 有时候表现不同?

本文将一一解答这些问题,并通过实战代码加深理解。


变量是什么?

在 Python 中,变量不是存储数据的容器,而是对象的引用。可以把变量理解为“指向对象的标签”。

a = 10
b = a
print(id(a), id(b))  # 两者的内存地址相同

ab 都指向整数对象 10,当执行 a = 20 时,a 并不会修改原对象,而是重新指向了一个新的对象。


Python 的数据类型

Python 内置了丰富的数据类型,主要分为两大类:不可变类型可变类型

数字类型

x = 10        # int
y = 3.14      # float
z = 3 + 4j    # complex

特点:

  • 数字类型为不可变对象。
  • 对数字重新赋值会创建新对象。

字符串类型

s = "Hello"
print(s.upper())  # "HELLO"
print(s)          # 原字符串未被修改

字符串是不可变对象,每次操作都会生成新对象。


布尔类型

is_ready = True
print(isinstance(is_ready, bool))  # True

布尔值是特殊的整数类型,True 等价于 1False 等价于 0


列表、元组、字典、集合

lst = [1, 2, 3]        # 可变
tpl = (1, 2, 3)        # 不可变
dct = {"a": 1}         # 可变
st  = {1, 2, 3}        # 可变

可变对象可以被原地修改,而不可变对象修改后会返回新的对象。


变量与内存

id() 函数与内存地址

id() 用于返回对象的“内存标识”,通常是对象的内存地址。

a = 10
b = 10
print(id(a), id(b))  # 相同(小整数缓存)

a = 20 时,a 指向了一个新的内存地址。


可变对象与不可变对象

  • 可变对象(列表、字典、集合):原地修改不会更换内存地址。
  • 不可变对象(整数、字符串、元组):每次修改会生成新对象。
lst = [1, 2, 3]
print(id(lst))
lst.append(4)
print(id(lst))  # 地址不变s = "abc"
print(id(s))
s += "d"
print(id(s))    # 地址发生变化

引用计数与垃圾回收

Python 使用 引用计数 + 垃圾回收机制 管理内存。

import sysa = [1, 2, 3]
print(sys.getrefcount(a))  # 查看引用计数

当对象的引用计数为 0 时,Python 的垃圾回收器会自动释放该对象。


小整数缓存与字符串驻留

Python 会对一些对象进行缓存,以提升性能:

  • 小整数缓存-5 ~ 256 的整数对象会被缓存。
  • 字符串驻留:常见短字符串会被重用。
a = 256
b = 256
print(a is b)  # Truex = "hello"
y = "hello"
print(x is y)  # True

is 与 == 的区别

  • is:判断两个变量是否指向同一个对象(比较内存地址)。
  • ==:判断两个对象的值是否相等。
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b)  # True(值相等)
print(a is b)  # False(内存地址不同)

深拷贝与浅拷贝

当我们复制对象时,要注意 Python 的拷贝机制:

import copylst1 = [[1, 2], [3, 4]]
lst2 = lst1.copy()        # 浅拷贝
lst3 = copy.deepcopy(lst1) # 深拷贝lst1[0][0] = 99
print(lst2)  # [[99, 2], [3, 4]] 受影响
print(lst3)  # [[1, 2], [3, 4]] 不受影响
  • 浅拷贝:只复制最外层引用,内部对象共享。
  • 深拷贝:递归复制所有对象。

内存优化技巧

  1. 避免不必要的对象拷贝

    # 不要频繁用 + 拼接字符串
    result = []
    for i in range(1000):result.append(str(i))
    print("".join(result))
    
  2. 使用生成器减少内存占用

    def gen():for i in range(1000):yield i
    for x in gen():print(x)
    
  3. 利用 __slots__ 限制对象属性

    class Person:__slots__ = ('name', 'age')
    
  4. 及时清理无用引用

    del obj
    

实战示例

# 变量与内存地址示例
x = [1, 2, 3]
y = x
print(id(x), id(y))  # 两者相同y.append(4)
print(x)             # [1, 2, 3, 4],因为是同一个列表引用# 不可变对象示例
a = 10
b = a
print(id(a), id(b))  # 相同
a += 1
print(id(a), id(b))  # a 变了,b 不变

总结

  • Python 变量是“标签”,指向内存中的对象。
  • 不可变对象(数字、字符串、元组)每次修改会生成新对象。
  • 可变对象(列表、字典、集合)原地修改内存地址不变。
  • Python 使用引用计数和垃圾回收机制管理内存。
  • 小整数缓存、字符串驻留是性能优化手段,但不要依赖内部实现。
  • 理解 is==、浅拷贝与深拷贝是写好 Python 的关键。

免责声明

本文仅用于学习与交流,代码示例请在个人或受控环境中运行。作者不对因使用本文内容而造成的任何直接或间接损失负责,转载请注明出处。

http://www.lryc.cn/news/607924.html

相关文章:

  • Android13文件管理USB音乐无专辑图片显示的是同目录其他图片
  • 【NLP舆情分析】基于python微博舆情分析可视化系统(flask+pandas+echarts) 视频教程 - 微博舆情数据可视化分析-热词情感趋势柱状图
  • 机器学习 —— 决策树
  • 从C++0基础到C++入门(第十五节:switch语句)
  • 计算机网络:为什么IPv6没有选择使用点分十进制
  • 如何修复非json数据
  • Gemini CLI
  • 深入 Go 底层原理(五):内存分配机制
  • 操作系统-lecture5(线程)
  • Vue3核心语法基础
  • 【大模型入门】3.从头实现GPT模型以生成文本
  • 相对路径 绝对路径
  • UniappDay07
  • sqli-labs:Less-19关卡详细解析
  • Qt 槽函数被执行多次,并且使用Qt::UniqueConnection无效【已解决】
  • 24黑马SpringCloud的Docker本地目录挂载出现相关问题解决
  • Tushare对接OpenBB分析A股与港股市场
  • 解锁智能油脂润滑系统:加速度与温振传感器选型协同攻略
  • 深度学习核心:卷积神经网络 - 原理、实现及在医学影像领域的应用
  • 【Java】在一个前台界面中动态展示多个数据表的字段及数据
  • 定制开发开源AI智能名片S2B2C商城小程序的特点、应用与发展研究
  • 自进化智能体综述:通往人工超级智能之路
  • SpringBoot IOC
  • C++之vector类的代码及其逻辑详解 (中)
  • 【自动化运维神器Ansible】YAML语法详解:Ansible Playbook的基石
  • vue引入阿里巴巴矢量图库的方式
  • Kotlin协程极简教程:5分钟学完关键知识点
  • docker desktop入门(docker桌面版)(提示wsl版本太低解决办法)
  • 【MySQL】增删改查操作 —— CRUD
  • Elasticsearch 混合检索一句 `retriever.rrf`,把语义召回与关键词召回融合到极致