python易错盲点排查之+=与+的区别分析以及一些赋值运算踩过的坑
问题1. int和list是不一样的
>>> a=1 >>> b=a >>> a+=1 >>> a,b (2, 1) >>> a=[1,2,3,4] >>> b=a >>> a+=[5] >>> a,b ([1, 2, 3, 4, 5], [1, 2, 3, 4, 5])
通俗地讲,类型为int时,a和b是“不一样的”;类型为list时,a和b是“一样的”。术语叫做immutable和mutable,具体原理在这个节点不必深究。
问题1.1. 我们通常运行b=a这一语句时,会直觉地认为,b和a已经不一样了。
>>> a=[[1],[2],[3],[4]] >>> b+=a[0:2] >>> b [1, 2, 3, 4, [1], [2]] >>> a=[[1],[2],[3],[4]] >>> b=[] >>> b+=a[0:2] >>> a,b ([[1], [2], [3], [4]], [[1], [2]]) >>> b[0] [1] >>> b[0][0]='changed!' >>> # You don't expect a to change >>> # However >>> a, b ([['changed!'], [2], [3], [4]], [['changed!'], [2]])
可以看到,a[0]的[1]和b[0]的[1]是“一样的”,因为改变b[0]就会改变a[0](注意不是改变b,是改变b[0]。改变b不会对a有任何影响)
问题2. list的情况下,a+=b和a=a+b是不一样的:
>>> a=[1,2,3,4] >>> b=a >>> a+=[5] >>> a,b ([1, 2, 3, 4, 5], [1, 2, 3, 4, 5]) >>> a=[1,2,3,4] >>> b=a >>> a=a+[5] >>> a,b ([1, 2, 3, 4, 5], [1, 2, 3, 4])
同样通俗地讲,在+=的情况下,a还是原来的a,和b“一样”;在+的情况下,a已经不是原来的a了,和b“不一样”。
问题3. 如果要让+=和+行为一致,应该怎么做?
>>> import copy >>> a=[1,2,3,4] >>> b=copy.deepcopy(a) >>> a+=[5] >>> a,b ([1, 2, 3, 4, 5], [1, 2, 3, 4])
这与问题2中a=a+b的情况结果一致了。当对list进行b=a时,实际上进行的是“引用”操作;只有使用b=copy.deepcopy(a)才是进行我们通常期望的“拷贝”操作。
问题4. 回到问题中的代码,当k=1时,以下代码:
subset += (elements[0:size])
根据问题1.1,subset与elements是“一样的”,因此未来改变subset的元素的操作有可能改变elements的元素。
到这行代码时,注意set就是递归传递过来的subset:
#set[j] += (elements[i]) #Why Elements change here? set[j] = set[j] + (elements[i])
根据问题2,+=中set[j]依然是原来的set[j],也就可能是elements的元素。因此
set[j] += elements[i]
可能会等价于
elements[*] += elements[i]
一旦改变了elements的元素,结果自然就不对了。
怎么解决这个问题?根据问题3,只要保证set与elements是“不一样的”,就符合程序的逻辑。因此将
subset += (elements[0:size])
改为(记得import copy)
subset += copy.deepcopy(elements[0:size])
就能在+=的情况下正常运行了。
总结:在python中,list类型的赋值b=a进行的引用操作,而非拷贝操作,在需要拷贝操作时,需要加上b=copy.deepcopy(a)。(copy.copy和copy.deepcopy的区别超出问题范畴,有兴趣可以google)
作 者:Angel_Kitty
出 处:https://www.cnblogs.com/ECJTUACM-873284962/
关于作者:阿里云ACE,目前主要研究方向是Web安全漏洞以及反序列化。如有问题或建议,请多多赐教!
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是作者坚持原创和持续写作的最大动力!
欢迎大家关注我的微信公众号IT老实人(IThonest),如果您觉得文章对您有很大的帮助,您可以考虑赏博主一杯咖啡以资鼓励,您的肯定将是我最大的动力。thx.
我的公众号是IT老实人(IThonest),一个有故事的公众号,欢迎大家来这里讨论,共同进步,不断学习才能不断进步。扫下面的二维码或者收藏下面的二维码关注吧(长按下面的二维码图片、并选择识别图中的二维码),个人QQ和微信的二维码也已给出,扫描下面👇的二维码一起来讨论吧!!!
欢迎大家关注我的Github,一些文章的备份和平常做的一些项目会存放在这里。