python弱点-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. 如果要让+=和+行为一致,应该怎么做?

>>> importcopy>>> 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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值