一、内存分配
说到Python的深浅拷贝,就要先说下Python的内存分配
当你为变量赋值时,会先开辟一片内存,存放该值,将变量指向这个值
x = 3
当你将x或3值赋予y时,并不会重新开辟新的内存,而是直接指向之前值3:
# y = 3
y = x
你也可以用函数id()来查看地址是相等的:
x = 3
print id(x)
# output 7496216
y = x
print id(y)
# output 7496216
当再次对x赋值为4的时候,会新开辟一片内存,存放4,并且把x重新指向4:
地址也变化了不一样了:
x = 3
print id(x)
# output 56189464
y = x
print id(y)
# output 56189464
x = 4
print id(x)
# output 56189440
二、深浅拷贝
深浅拷贝需要引入python的内置模块copy
import copy
-
对于平常的数值、字符串是没有任何影响的,不管是深拷贝还是浅拷贝都是一样,内存地址不变:
import copy x = "test" print id(x) # output 53921792 t = x print id(t) # output 53921792 y = copy.copy(x) print id(y) # output 53921792 z = copy.deepcopy(x) print id(z) # output 53921792
-
针对list时,深拷贝z和浅拷贝y会重新开辟了一片内存地址,但是赋值的t不会重新分配,而是直接指向x的值
import copy x = [2, 3, 5, 8] print id(x) # output 48175944 t = x print id(t) # output 48175944 y = copy.copy(x) print id(y) # output 48231624 z = copy.deepcopy(x) print id(z) # output 48174728
当对x内部的元素(非list,dict元素)进行赋新值或修改时,深浅拷贝的值都不会随着x变化而变化,只有赋值类型t随x变化而变化:
print id(z) x.append(9) x[2] = 4 print x print t print y print z #output #[2, 3, 4, 8, 9] #[2, 3, 4, 8, 9] #[2, 3, 5, 8] #[2, 3, 5, 8]
当list中存在list时
import copy a = [1, 10] x = [2, 3, 5, 8, a] t = x y = copy.copy(x) z = copy.deepcopy(x) print x print t print y print z #output #[2, 3, 5, 8, [1, 10]] #[2, 3, 5, 8, [1, 10]] #[2, 3, 5, 8, [1, 10]] #[2, 3, 5, 8, [1, 10]]
对list中的list进行修改时,你会发现赋值的t和浅拷贝的y会随着List a的改变而改变,而深拷贝不受影响,这是因为浅拷贝只对List x本身进行了拷贝,没有对它内部的List a进行拷贝,只是引用;而深拷贝是对所有对象重新开辟内存,所以不受影响
x[4].append(6) print a print x print t print y print z #output #[1, 10, 6] #[2, 3, 5, 8, [1, 10, 6]] #[2, 3, 5, 8, [1, 10, 6]] #[2, 3, 5, 8, [1, 10, 6]] #[2, 3, 5, 8, [1, 10]]
对于List来说,浅拷贝等价于如下的赋值:
import copy x = [2, 3, 5, 8] c = x[:] #等价于 c = copy.copy(x)
额外List的小技巧;
x = [1, 2, 3, 4] # 从后边加入元素 x[len(x):] = [5, 6, 7] print(x) # 从前边增加元素 x[:0] = [-1, 0, 2, 3] print(x) # 移除元素 x[1:-1] = [] print(x) #output #[1, 2, 3, 4, 5, 6, 7] #[-1, 0, 2, 3, 1, 2, 3, 4, 5, 6, 7] #[-1, 7]