刷lc题的时候,老踩这种坑,索性搞懂。
先有概念:
1、python里面的所有元素都是对象,实例化一个对象就会开辟新的内存空间,然后返回一个引用给你。
2、a = 3。这里实例化了一个对象3,用变量名a表示。需要明确a不是对象本身,a只是这个对象3的引用。(回忆一下c++里面的指针和引用)
可变对象和不可变对象
可变对象和不可变对象的本质区别就是:对象本身的值可不可变。
可变对象:可变对象的值是可以原地 (inplace) 改变的,我们可以通过引用 (变量名) 来操作可变对象,使得它的值原地变化(即不开辟新的内存空间,地址不变)。
包括:list、set、dict(添加值我们不把它看成开辟“新”的内存空间,因为地址没变)。
不可变对象:不可变对象的值是不能改变的。如果引用 (变量名) 如果想要改变值,那不好意思,请你找新的对象去吧!(也就是会实例化新的对象,开辟新的内存空间,产生一个新的地址)
包括:int、str、float、tuple
特殊:int值比较小时[-5,257),会共享对象
Demo(此图出现太多,不明出处):
不可变对象 int
可变对象 list
+= 和 =+
这两个操作符,和可变/不可变对象有密切联系。
+=:调用对象的__iadd__方法,若不存在,才调用__add__方法;
=+:直接调用对象的__add__方法。
__iadd__方法直接在原地 (inplace) 修改对象的值,返回值为None,因此引用的地址不变;而__add__方法会返回一个新的对象,原对象不变。
和可变/不可变对象的联系:
一般情况下,可变对象有__iadd__方法,而不可变对象只有__add__方法。
另:对list而言,+= 和 extend() 等价。
Demo:
坑
坑1:python 解二叉树题遇到的问题
坑2:dp初始化二维数组时,下面注释里面那种写法是错的。
class
为什么呢?因为int是不可变对象,复制出来都是新的对象,所以第一维没有问题。而list复制的只是引用,第二维看似复制了很多次,实际上都指向同一个对象。
所以可以用*复制不可变对象,但千万不要用来复制可变对象!
错误(左),正确(右)
深Copy和浅Copy
这篇文章写得很好,就不重复造轮子了。
张小鸡:5张图彻底理解Python中的浅拷贝与深拷贝zhuanlan.zhihu.com
总结一下:
1、赋值
赋值操作,其实就是给一段内存地址贴标签。
对于不可变对象,=、copy、deepcopy三者等价。
2、浅拷贝
拷贝父对象的副本,但不会拷贝对象的内部的子对象。
或者说浅拷贝只是拷贝了原始元素的引用(内存地址),拷贝对象的值是否会随着被拷贝对象变化,仅取决于原始元素是可变对象还是不可变对象。
3、深拷贝
完全拷贝了父对象及其子对象。
深拷贝复制的不只是原始元素的引用,而是整个原始元素对象。因此,拷贝对象和被拷贝对象的值相互独立。
参考:
关于python中的+、+=、*、*=
Python 中 a+=b 和 a=a+b 的区别有哪些? - 刘志军的回答 - 知乎
Python中的可变对象与不可变对象
5张图彻底理解Python中的浅拷贝与深拷贝