一、内存分配
说到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]