先来做两道题,看看你能全对吗?
题目一:
a =10b = ab =20print(a)# 输出?
题目二:
a =[1,2,3]b = ab.append(4)print(a)# 输出?
答案分别是 10 和 [1, 2, 3, 4]。
为什么同样是“把 a 赋值给 b”,修改 b 后,第一个 a 没变,第二个 a 却变了?
如果你能秒懂,那这篇文章对你来说可能是复习。
如果你犹豫了,甚至答错了,那这 5 分钟,将彻底改变你对 Python 变量的认知。
一、你脑海中的“变量”可能是错的
很多初学者把变量想象成一个盒子:
这个模型在大多数时候能工作,但一旦遇到列表、字典,就会翻车。
因为 Python 的变量根本不是盒子,而是“便利贴”。
便利贴模型:
每个对象(比如数字 10、列表 [1,2,3])都有一块独立的内存空间
变量名就是一张便利贴,贴在对象上
b = a 不是复制对象,而是再拿一张新便利贴,贴在同一个对象上
所以当你修改那个对象时,所有贴在上面的便利贴(变量名)都能看到变化。
二、不可变对象 vs 可变对象
为什么数字和列表表现不同?因为 Python 中的对象分两类:
① 不可变对象(int, float, str, tuple, bool)
创建后内容不能改。你每次“修改”其实是新建了一个对象,然后把标签撕下来贴到新对象上。
a =10# 对象 10,贴上 ab = a # b 也贴在对象 10 上b =20# 新建对象 20,把 b 撕下来贴到 20 上# a 仍然贴在 10 上,所以 a 还是 10
② 可变对象(list, dict, set, 自定义类实例)
创建后内容可以原地修改,不需要新建对象。
a =[1,2,3]# 创建列表对象,贴上 ab = a # b 也贴在这个列表上b.append(4)# 原地修改列表,所有标签都能看到变化# a 和 b 都贴在同一对象上,所以 a 也变成了 [1,2,3,4]
三、图解真相(建议你脑补或画一下)
场景一:不可变
内存中有一个对象 10,标签 a 指向它。
执行 b = a,内存中还是只有对象 10,现在多了一个标签 b 指向它。
执行 b = 20,内存中新建对象 20,然后把标签 b 移过去,a 仍然指向 10。
场景二:可变
内存中有一个列表对象 [1,2,3],标签 a 指向它。
执行 b = a,同一个列表对象,多了标签 b。
执行 b.append(4),没有新建列表,而是修改了那个列表的内部内容。a 和 b 指向的还是那个列表,所以都变了。
四、这个知识有什么用?
1. 函数传参时,小心修改外部数据
def add_item(lst): lst.append(999)my_list =[1,2,3]add_item(my_list)print(my_list)# [1,2,3,999] 原列表被改了!
如果不希望原列表被改,传入副本:add_item(my_list.copy())。
2. 拷贝列表时要分清深浅
不过对大学生来说,先掌握浅拷贝就够用了。
五、避开这 3 个常见误区
误区①:以为 = 会复制数据
真相:= 只复制引用,不复制数据。要复制数据,请用 .copy()、list() 或切片。
误区②:认为不可变对象“不能改”就等于“值不变”
其实 a = a + 1 会创建新对象,原对象没变。这并不矛盾,只是你“重新贴标签”了。
误区③:混淆 == 和 is
== 比较值是否相等
is 比较是否是同一个对象(内存地址)
a =[1,2,3]b =[1,2,3]print(a == b)# True,值一样print(a is b)# False,不是同一个对象
六、一句话记住今天的内容
Python 变量是贴在对象上的便利贴,不是存放东西的盒子。
可变对象可以原地修改,所有标签同步变化;不可变对象只能新建,原标签不受影响。
理解了这句话,你就能预测任何赋值操作的结果,再也不会被列表拷贝、函数传参搞晕了。
🎁 福利:Python 入门大礼包(限时免费领)
关注我的公众号 ,在后台回复关键词 学习 ,即可免费领取:
📢 最后的最后
如果觉得有用,点个「赞」和「在看」,让更多朋友看到。