【第三章】变量也疯狂:深入剖析 Python 数据类型与内存原理
Python 中的一切皆对象,但变量真的“存储”数据吗?为什么
a = 10
改成a = 20
后,内存地址会变?本文将带你从基础到底层,彻底搞懂 Python 变量、数据类型与内存管理的秘密!
目录
- 前言
- 变量是什么?
- Python 的数据类型
- 数字类型
- 字符串类型
- 布尔类型
- 列表、元组、字典、集合
- 变量与内存
- id() 函数与内存地址
- 可变对象与不可变对象
- 引用计数与垃圾回收
- 小整数缓存与字符串驻留
- is 与 == 的区别
- 深拷贝与浅拷贝
- 内存优化技巧
- 实战示例
- 总结
- 免责声明
前言
Python 虽然是高级语言,但理解它的变量与内存模型是写出高效、可控代码的基础。很多初学者会被以下问题困扰:
- 为什么
a = 10
和b = 10
的id
相同? - 为什么列表可以被原地修改,而整数不行?
- Python 的垃圾回收机制到底怎么工作?
- 为什么
is
和==
有时候表现不同?
本文将一一解答这些问题,并通过实战代码加深理解。
变量是什么?
在 Python 中,变量不是存储数据的容器,而是对象的引用。可以把变量理解为“指向对象的标签”。
a = 10
b = a
print(id(a), id(b)) # 两者的内存地址相同
a
和b
都指向整数对象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
等价于 1
,False
等价于 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]] 不受影响
- 浅拷贝:只复制最外层引用,内部对象共享。
- 深拷贝:递归复制所有对象。
内存优化技巧
-
避免不必要的对象拷贝
# 不要频繁用 + 拼接字符串 result = [] for i in range(1000):result.append(str(i)) print("".join(result))
-
使用生成器减少内存占用
def gen():for i in range(1000):yield i for x in gen():print(x)
-
利用
__slots__
限制对象属性class Person:__slots__ = ('name', 'age')
-
及时清理无用引用
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 的关键。
免责声明
本文仅用于学习与交流,代码示例请在个人或受控环境中运行。作者不对因使用本文内容而造成的任何直接或间接损失负责,转载请注明出处。