当前位置:首页>python>Day06 Python 可变类型 vs 不可变类型

Day06 Python 可变类型 vs 不可变类型

  • 2026-10-21 13:29:49
Day06 Python 可变类型 vs 不可变类型

一、先搞懂:核心判断标准(一句话记住)

区分可变类型和不可变类型,只看一个核心点:当变量的值发生改变时,对应的内存地址是否保持不变(用id()函数可查看变量的内存地址,唯一标识一个对象)。

用两个通俗比喻理解:

  1. 不可变类型:像「一次性饭盒」,饭菜(值)吃完想换,只能重新买一个新饭盒(新内存地址),旧饭盒留着不动;
  2. 可变类型:像「可重复使用的保鲜盒」,饭菜(值)可以随时更换、添加,不用换盒子(内存地址不变)。
二、两类数据类型的详细拆解(附示例,简单好懂)
类型分类
核心特性
包含的数据类型
不可变类型
值改变 → 内存地址改变(创建新对象,原对象不变)
整数、浮点数、字符串、元组
可变类型
值改变 → 内存地址不变(修改原对象,不创建新对象)
列表、字典、集合

1. 不可变类型:值变,地址必变

这类类型的对象创建后,就像被「封印」了,无法修改内部的值,看似「修改」其实是创建了一个全新的对象,内存地址也会随之更新。

# 示例1:字符串(不可变)s = "hello"print("修改前值:", s)print("修改前地址:", id(s))  # 打印内存地址# 看似修改字符串,实则创建新对象s += " world"print("修改后值:", s)print("修改后地址:", id(s))  # 地址与修改前不同,证明创建了新对象# 示例2:元组(不可变,重点避坑)t = (1, 2, 3)print("\n修改前值:", t)print("修改前地址:", id(t))# 元组的+运算,看似修改,实则创建新元组t += (4, 5)print("修改后值:", t)print("修改后地址:", id(t))  # 地址改变,原元组未被修改
  • 元组的「不可变」是指「元素不可修改」,如果元组内包含列表(可变类型),列表内部的值可以修改(地址仍不变);
  • 不可变类型的优势:数据安全,不易被意外篡改,可作为字典的键(后续详解)。

2. 可变类型:值变,地址不变

这类类型的对象创建后,内部的值可以自由增删改,修改过程中不会创建新对象,内存地址始终保持不变,直接在原对象上操作。

# 示例1:列表(可变)lst = [1, 2, 3]print("修改前值:", lst)print("修改前地址:", id(lst))# 直接修改原列表(增、删、改均可)lst.append(4)  # 末尾添加元素lst[0] = 100   # 修改索引0的元素print("修改后值:", lst)print("修改后地址:", id(lst))  # 地址与修改前相同,证明修改原对象# 示例2:字典(可变)dic = {"name": "Python"}print("\n修改前值:", dic)print("修改前地址:", id(dic))# 直接修改原字典dic["age"] = 30  # 添加键值对dic["name"] = "Java"  # 修改已有键的值print("修改后值:", dic)print("修改后地址:", id(dic))  # 地址不变,修改原对象
  • 列表的+=、*=运算会直接修改原列表,地址不变;而lst = lst + [4,5]是创建新列表,地址会改变,日常开发注意区分;
  • 可变类型的优势:灵活高效,修改数据无需创建新对象,节省内存。
补充
a += 1 与 a = a + 1 的核心区别

一、先结论:对不可变类型无差异,对可变类型有本质区别

一句话总结核心差异:

  • 针对不可变类型(int、float、str、tuple):两者功能完全一致,都是创建新对象,内存地址都会改变;
  • 针对可变类型(list、dict、set,重点是列表):两者有本质区别,a += 1(对应列表a += b)修改原对象,a = a + 1(对应列表a = a + b)创建新对象。

注:a += 1 中的1是数字,仅适用于数字类型(不可变),针对列表等可变类型,常用形式是a += b(b为列表),我们重点围绕「数字类型」和「列表类型」展开,覆盖核心场景。

二、拆解 1:不可变类型(以整数int为例)—— 两者无差异

对于整数、浮点数、字符串等不可变类型,a += 1 和 a = a + 1 都是「先计算新值,再创建新对象,最后让变量a指向新对象」,内存地址都会改变,功能完全一致。

# 不可变类型:inta = 10print("初始值:", a)print("初始地址:", id(a))# 方式1:a = a + 1a1 = a  # 保留初始值,用于对比a1 = a1 + 1print("\na = a + 1 后值:", a1)print("a = a + 1 后地址:", id(a1))# 方式2:a += 1a2 = a  # 保留初始值,用于对比a2 += 1print("\na += 1 后值:", a2)print("a += 1 后地址:", id(a2))
运算结果:初始值: 10初始地址: 140705267855616a = a + 1 后值: 11a = a + 1 后地址: 140705267855648a += 1 后值: 11a += 1 后地址: 140705267855648
  • 不可变类型(int、str 等):a += 1 与 a = a + 1 无差异,均创建新对象,地址改变;
  • 可变类型(list 等):a += b 就地修改原对象(地址不变),a = a + b 创建新对象(地址改变);
  • 核心逻辑:结合「可变 / 不可变类型」的内存特性,就能轻松理解两者的差异,避免踩坑。

最新文章

随机文章