Jamie's Blog

Talk is cheap, show me the code.

Shallowcopy and Deepcopy

赋值操作认识

1.赋值是将一个对象的地址赋值给一个变量,让变量指向该地址

2.修改不可变对象(str、tuple)需要开辟新的空间

3修改可变对象(list等)不需要开辟新的空间

浅拷贝( 新瓶装旧酒 )

浅拷贝仅仅复制了容器中元素的地址

浅拷贝是在另一块地址中创建一个新的变量或容器,但是容器内的元素的地址均是源对象的元素的地址的拷贝。也就是说新的容器中指向了旧的元素( 新瓶装旧酒 )

1
2
3
4
5
6
7
8
9
a = ['hello',[1,2,3]]
b = a[:] #浅拷贝
print('源对象a--{}:{}'.format(a,[id(x) for x in a]))
print('浅拷贝对象b--{}:{}'.format(b,[id(x) for x in b]))
print('修改浅拷贝对象b')
b[0] = 'world'
b[1].append(4)
print('修改后源对象a--{}:{}'.format(a,[id(x) for x in a]))
print('修改后浅拷贝对象b--{}:{}'.format(b,[id(x) for x in b]))
源对象a--['hello', [1, 2, 3]]:[2924681864392, 2924682934600]
浅拷贝对象b--['hello', [1, 2, 3]]:[2924681864392, 2924682934600]
修改浅拷贝对象b
修改后源对象a--['hello', [1, 2, 3, 4]]:[2924681864392, 2924682934600]
修改后浅拷贝对象b--['world', [1, 2, 3, 4]]:[2924682621760, 2924682934600]

改变前后,可变的list地址都是一样的
改变前后,不变的str地址有变化

深拷贝(新瓶装新酒)

深拷贝,完全拷贝了一个副本,容器内部元素地址都不一样

深拷贝是在另一块地址中创建一个新的变量或容器,同时容器内的元素的地址也是新开辟的,仅仅是值相同而已,是完全的副本。也就是说( 新瓶装新酒 )。

1
2
3
4
5
6
7
8
9
10
from copy import deepcopy
a = ['hello',[1,2,3]]
b = deepcopy(a) #深拷贝
print('源对象a--{}:{}'.format(a,[id(x) for x in a]))
print('浅拷贝对象b--{}:{}'.format(b,[id(x) for x in b]))
print('修改深拷贝对象b')
b[0] = 'world'
b[1].append(4)
print('修改后源对象a--{}:{}'.format(a,[id(x) for x in a]))
print('修改后浅拷贝对象b--{}:{}'.format(b,[id(x) for x in b]))
源对象a--['hello', [1, 2, 3]]:[2924681864392, 2924682934088]
浅拷贝对象b--['hello', [1, 2, 3]]:[2924681864392, 2924681631816]
修改深拷贝对象b
修改后源对象a--['hello', [1, 2, 3]]:[2924681864392, 2924682934088]
修改后浅拷贝对象b--['world', [1, 2, 3, 4]]:[2924682621200, 2924681631816]

深拷贝就是将里面引用的对象重新创建了一遍并生成了一个新的一系列引用。

基本上是这样的,但是对于字符串、数字等不可修改的对象来说,重新创建一份似乎有点浪费内存,反正你到时要修改的时候都是新建对象,刷新引用的。所以还用原来的引用也无所谓,还能达到节省内存的目的。

所以上面的例子中,深拷贝后的b中第一个元素是字符串,所以还是用了原来的引用

元素不可变的保持原来的引用

元素可变的马上创建一个一模一样的

不可变的元素修改后创建新对象,再刷新引用

浅拷贝的几种方式

1
2
3
4
5
6
7
# 分片表达式能返回一个新的对象拷贝

L = [1,2,3,4,5]
C = L[1:3]
C[0] = 8
print(C)
print(L)
[8, 3]
[1, 2, 3, 4, 5]
1
2
3
4
5
6
7
# 字典的copy方法也能够实现字典的完全复制

D = {'a':1, 'b':2}
B = D.copy()
B['a'] = 888
print(B)
print(D)
{'a': 888, 'b': 2}
{'a': 1, 'b': 2}
1
2
3
4
5
6
7
# 内置函数list可以生成拷贝

L = [1,2,3,4]
C = list(L)
C[0] = 888
print(C)
print(L)
[888, 2, 3, 4]
[1, 2, 3, 4]

Proudly powered by Hexo and Theme by Hacker
© 2019 Jamie