一、赋值
在python中,对象的赋值就是简单的引用,a = [1,2,3], b=a, 在上述情况下,a和b是一样的,他们指向同一片内存,b不过是a的别名,是引用,我们可以使用b is a 去判断,返回True,表名他们地址相同内容也相同,也可以使用id()函数来查看.看两个列表地址是否相同.
赋值操作(包括对象作为参数、返回值),不会开辟新的内存空间,他只是赋值了对象的引用.也就是除了b这个名字之外,没有其他的内存开销,修改了a也就影响了b,修改了b,也就影响了a.
二、浅拷贝(shallowcopy)
浅拷贝会创建新的对象,其内容非原对象本身的引用,而是原对象内第一层对象的引用,
浅拷贝有三种形式:
切片操作:b = a[:]或者b = [x for x in a];
工厂函数:b = list(a);
copy函数:b = copy.copy(a)
浅拷贝产生的列表b不再是列表a了,使用is判断可以发现他们不是同一个对象,使用id查看,他们也不指向同一片内存空间,但是当我们使用id(x)for x in a 和id(x) for x in b 来查看a和b中元素地址时,可以看到二者包含的元素的地址时相同的.
在这种情况下列表a 和列表b是不同的对象,修改b理论上不会影响到列表a,
但是要注意的是浅拷贝之所以只拷贝了一层,在列表a中有一个嵌套的list,如果我们修改了它,情况就不一样了,比如:a[3].append(“4”),查看列表b也发生了变化,这是因为我们修改了嵌套的list,修改外层元素,会修改它的引用,让他指向别的位置,修改嵌套列表中的元素,地址未发生变化,指向的都是用一个位置
三、深拷贝(deepcopy)
深拷贝只是一种形式,copy模块中的deepcoopy()函数,深拷贝拷贝了对象的所有元素,包括多层嵌套的元素,因此他的时间和空间开销要高.
同样的对列表a,如果使用b= copy.deepcopy(a),再修改列表b也不会影响到列表a,即使嵌套的列表具有更深的层次,也不会产生任何影响,因为深拷贝拷贝出来的对象根本就是一个全新的对象,不再与原来的对象有任何的联系
四、拷贝的注意点
对于非容器类型,如数字,字符,以及其他的’’原子’’类型,没有拷贝一说,产生的都是原对象的引用.
如果元组变量值包含原子类型的对象,即使采用了深拷贝,也只能得到浅拷贝.因为元组是不可变类型.
如果拷贝对象为不可变类型,深浅拷贝都会引用地址,如果是嵌套类型,浅拷贝只关心顶层的类型,顶层为不可变类型,就引用地址,而深拷贝,必须对象类型都为不可变类型,才可以引用地址,否则会重新开辟新空间才拷贝数据。
只有可变类型或者"含有可变类型"的数据可以深拷贝,结果就是将原有的值复制一份,同时开辟新的内存空间存放这些数据