Python中的浅拷贝、深拷贝
1、定义
赋值:Python中赋值语句总是创建对象的引用,而不是复制对象。因此,Python中的变量更像是指针,而不是数据储存区域。当把值赋给另一个变量的时候,Python并没有拷贝这个对象,只是拷贝了这个对象的引用而已。
拷贝:在业务中有时我们需要复制一个对象,但是又不想对原对象产生副作用,那就不能通过赋值给新变量来解决了(赋值不是拷贝一个对象)。
浅拷贝(Shallow Copy):python拷贝一般都是浅拷贝,拷贝时,只拷贝父对象,不会拷贝对象的内部的子对象,因此,源对象与拷贝对象会引用同一个子对象。
深拷贝():使用copy模块的deepcopy函数,递归拷贝对象中包含的子对象,源对象和拷贝对象所有的子对象也不相同。
可变对象:对象的内容是可变的,如:列表、字典
不可变对象:对象的内容是不可变的,如:字符串、元组、数字
2、浅拷贝的实现
1.直接赋值
>>> a = [1,2,3]
>>> b = a
>>> b.append(4)
>>> a
[1, 2, 3, 4]
>>> b
[1, 2, 3, 4]
>>> id(a)
2644782401608
>>> id(b)
2644782401608
2.切片
>>> c = [2,0,[1,9]]
>>> d = c[:]
>>> d[2][0] += 9
>>> c
[2, 0, [10, 9]]
>>> d
[2, 0, [10, 9]]
>>> id(c)
2644782518984
>>> id(d)
2644782399944
#外层地址不同
>>> id(c[2])
2644782254024
>>> id(d[2])
2644782254024
#内层地址相同
3.使用数据类型的copy
列表
>>> a=[1,2,3,['m','n']]
>>> b=a.copy()
>>> a[1]=8
>>> a
>>> b
[1, 8, 3, ['m', 'n']]
[1, 2, 3, ['m', 'n']]
#浅拷贝改变a的外层,b不会随之变化,因为他们的外层是两个独立的个体,互不影响
>>> a=[1,2,3,['m','n']]
>>> b=a.copy()
>>> a[3][0]='k'
>>> a
>>> b
[1, 2, 3, ['k', 'n']]
[1, 2, 3, ['k', 'n']]
#改变a的内层,b会随之变化,因为浅拷贝后ab的内层在一个内存地址里
字典
>>> data = {'user':'admin','num':[1,2,3]}
>>> data1 = data.copy()
>>> data
>>> data1
{'user': 'root', 'num': [1, 2, 3]}
{'user': 'admin', 'num': [1, 2, 3]}
>>> data['num'].remove(1)
>>> data
>>> data1
{'user': 'root', 'num': [2, 3]}
{'user': 'admin', 'num': [2, 3]}
#当源拷贝对象不止一级目录时,源对一级目录的子目录做任何改动,都会影响浅拷贝
4.使用 copy 模块的 copy 方法
>>> from copy import copy
>>> m = [1, 2, [3, 4]]
>>> n = copy(m)
>>> n[2][0] += 5
>>> m
>>> n
[1, 2, [8, 4]]
[1, 2, [8, 4]]
5.numpy中,传入参数为ndarray时,array()会拷贝原数据,开辟新的内存储存它,新建了一个ndarray对象。asarray与原参数共享一个内存
>>> import numpy as np
>>> x = [1,2,3,4,5,6]
>>> a = np.asarray(x)
>>> a = np.arange(3)
>>> b1 = np.asarray(a)
>>> a
>>> b1
[4 1 2]
[4 1 2]
6.numpy:ndarray.view
>>> import numpy as np
>>> e = np.array([-45,-66,2,25,99,-33])
>>> f = e.view()#f与e“共享视图”
>>> f.shape = (2,3)
>>> e[0] = 0
>>> e
array([ 0, -66, 2, 25, 99, -33])
>>> f
array([[ 0, -66, 2],
[ 25, 99, -33]])
>>> f[1,1] = 88
>>> f
array([[ 0, -66, 2],
[ 25, 88, -33]])
>>> e
array([ 0, -66, 2, 25, 88, -33])
3.深拷贝的实现
1.使用 copy 模块的 deepcopy 方法
import copy
>>> a = [1, 2, 3]
>>> b = copy.deepcopy(a)
>>> a
>>> b
[1, 2, 3]
[1, 2, 3]
>>> b.append(4)
>>> a
>>> b
[1, 2, 3]
[1, 2, 3, 4]
>>> id(a)
>>> id(b)
2644782458632
2644782879112
2.numpy切片与索引
使用整数序列,不和原始数组共享内存
>>> import numpy as np
>>> x = np.arange(10,1,-1)
>>> x
array([10, 9, 8, 7, 6, 5, 4, 3, 2])
>>> x[[3,3,1,8]]
array([7, 7, 9, 2])
>>> b = x[np.array([3,3,-3,8])]
>>> b
array([7, 7, 4, 2])
>>> b[2] = 100
>>> b
array([7, 7, 100, 2])
>>> x
array([10, 9, 8, 7, 6, 5, 4, 3, 2])
3.numpy:np.copy()
>>> import numpy as np
>>> e = np.array([ 0, -66, 2, 25, 88, -33])
>>> g = np.copy(e)
>>> g
array([ 0, -66, 2, 25, 88, -33])
>>> e[0] = 8
>>> g
array([ 0, -66, 2, 25, 88, -33])
>>> id(e)
>>> id(g)
2845384560192
2845384443424
4.总结
- 赋值一般为浅拷贝
- 浅拷贝利用copy
- 深拷贝利用deepcopy
- 浅拷贝只拷贝列表的外层列表,内层列表会跟随原列表进行改变,两者互相影响
- 深拷贝拷贝所有的数据,然后开辟了一个新的内存地址,跟原数据不在同一个地址,两者互不影响
- numpy中的深浅拷贝有其自己的规律