在多年开发和教学 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])
如果觉得这个输出结果是 {‘name’: ‘Pony’, ‘id’: 1} ,那么就掉进这个坑里了。
如果真的运行一下就会发现,team里面三个都是 {‘name’: ‘Crossin’, ‘id’: 2} , 而且,如果之后再更改任何一个的 name 或 id 属性,另外两个也会跟着变。
那么为什么呢?
在 Python 中,要把变量想象成一个标签,而不是一个容器!
什么意思?在某些语言中,变量确实像一个“容器”,你定义了某种类型的变量,就给你分配好这个容器,之后你给变量赋值,就像是往容器里装入不同的内容,但容器还是那个容器,不会变。你创建3个容器,赋给一样的值,他们也还是3个独立的容器。
但在 Python 中,这个理解是错误的!
Python 中的变量像是一个“标签”,你给一个变量赋值,就是把这个标签贴在一个对象上;重新赋值,就是撕下标签帖到另一个对象上。
给3个变量赋给一样的值,就相当于把3个标签贴在同一个对象上。
用例子来说明:
a = 1 b = 2 c = 1 # 再次赋值 a = b
示意图:

通过输出 id(相当于内存地址)也可以说明这点:

在赋值之后,其实并不是 a 的值发生了变化,而是 a 的地址发生了变化。
理解了这点之后,你就会明白2件事:
- 当你给一个变量重新赋值之后,它就不再是之前的那个变量,所有的操作不会再影响到之前的变量上
- 当你给多个变量赋值相同的变量,它们其实都是同一个,只要改动其中之一,其他的也会跟着变化。(注意,是改动而非重新赋值,比如修改对象属性)
这个原理,在有关函数的参数传递、拷贝对象时都会涉及到。
因此,回到最初的问题,三个重新赋值其实本质是三个共用同一地址。
本文转载自微信公众号 Crossin的编程教室 ,为以后避免踩坑而记录。
有时候一天长的像一生,
有时候一生短的像一天。
世界上没有两个相同的一天,
但每一天都适合开始,
适合离别,适合爱。
——周一周二


评论
753253 377488Following study a number of the websites with your web site now, and that i genuinely appreciate your method of blogging. I bookmarked it to my bookmark web site list and are checking back soon. Pls have a appear at my web page likewise and let me know if you agree. 622823
672594 248683Some genuinely good and valuable information on this site , besides I believe the style contains wonderful functions. 43460
770940 217633I cant say that I completely agree, but then again Ive never genuinely thought of it quite like that before. Thanks for giving me something to take into consideration when Im supposed to have an empty mind while trying to fall asleep tonight lol.. 202221
959992 887526Ive applied the valuable points from this page and I can definitely tell that it gives a lot of assistance with my present jobs. I would be extremely pleased to keep acquiring back in this web page. Thank you. 421964
157823 195688Good read, I just passed this onto a colleague who was performing a bit research on that. And he just bought me lunch since I located it for him smile So let me rephrase that: Thank you for lunch! 832023
552930 847174Good read, I just passed this onto a colleague who was doing some research on that. And he truly bought me lunch as I identified it for him smile So let me rephrase that: Thank you for lunch! 148433
921865 686283Wonderful internet site you got here! Yoo man wonderful reads, post some more! Im gon come back so greater have updated 499185
751237 411221You produced some decent points there. I looked online to the concern and discovered a lot of people is going in addition to employing your web site. 294182
647843 354793youre in point of fact a great webmaster. The internet site loading velocity is amazing. It seems that youre performing any distinctive trick. In addition, The contents are masterpiece. youve done a fantastic activity on this subject! 463854
55036 519131Some genuinely good and utilitarian info on this internet web site , likewise I believe the style and style contains superb features. 990913