在多年开发和教学 Python 的过程中,有一个 bug,出现的频率非常高,经常有人会踩坑:person = {'name': '', 'id': 0}
team = []
for i in range(3):
x = person
x['id'] = i
team.append(x)
team[0]['name'] = 'Jack'
team[1]['name'] = 'Pony'
team[2]['name'] = 'Crossin'
print(team[1])
一种很常见的错误,就是觉得 team 这里列表(list)里是三个独立的字典(dict)对象。然而看了输出你就会发现,列表中的三个元素长得一样。而且,如果你之后再更改任何一个的 name 或 id 属性,另外两个也会跟着变。为什么会这样?
在 Python 中,你要把变量想象成一个标签,而不是一个容器!
什么意思?在某些语言中,变量确实像一个“容器”,你定义了某种类型的变量,就给你分配好这个容器,之后你给变量赋值,就像是往容器里装入不同的内容,但容器还是那个容器,不会变。你创建3个容器,赋给一样的值,他们也还是3个独立的容器。
Python 中的变量像是一个“标签”,你给一个变量赋值,就是把这个标签贴在一个对象上;重新赋值,就是撕下标签帖到另一个对象上。你给3个变量赋给一样的值,就相当于把3个标签贴在同一个对象上。
在赋值之后,其实并不是 a 的值发生了变化,而是 a 的地址发生了变化。当你给一个变量重新赋值之后,它就不再是之前的那个变量,所有的操作不会再影响到之前的变量上
当你给多个变量赋值相同的变量,它们其实都是同一个,只要改动其中之一,其他的也会跟着变化。(注意,是改动而非重新赋值,比如修改对象属性)
这个原理,在有关函数的参数传递、拷贝对象时都会涉及到,前两天答疑群里就有同学遇到类似的困惑。有关这点,我之前曾写过几篇文章,再拿出来分享下。之前没看过的同学,强烈建议都看一下,因为你以后多少都会碰到类似的问题:
函数的参数传递
可变对象与不可变对象
关于深浅拷贝
顺便再通知下,我们这周日将开启新一期“Python零基础学习小组”,目前正在接受报名中。详情可见今天推送的第二条文章,或点击:
欢迎加入
Crossin的编程教室
crossincode.com