赋值:只复制对象的引用,不会开辟新的内存空间。其中一个被改变的时候,另一个也会被改变。
浅拷贝:创建新的对象,其内容是原对象的引用。
浅拷贝有三种形式:切片,工厂函数,copy模块中的copy函数。
举例:
lst = [1, 2, 3, 4]
# 切片
lc = lst[:]
lc = [item for item in lst]
# 工厂函数
lc = list(lst)
# copy函数
lc = copy.copy(lst)
浅拷贝只拷贝对象的第一层(最外层) ,内部元素拷贝的是引用。
浅拷贝分两种情况:
(1)当浅拷贝的值是不可变对象(元组,字符串,数值类型)时和“赋值”一样,对象的id值和原对象的id值相同。
(1)当浅拷贝的值是可变对象(列表,字典,集合)时,分两种情况:
内部元素都是不可变对象,浅拷贝的id值与原对象不同,改变其中一个的值不会影响另一个。
内部元素有可变对象,称这些元素为复杂子对象,如果改变复杂子对象的值,会影响另一个。
一、列表
赋值:赋值后的变量id值和原对象id值相同,改变其中一个会影响另一个。
lst = [1, 2, 3, 4]
lc = lst
print(id(lst) == id(lc)) # true
浅拷贝:创建新的对象,其id值和原对象id值不同,改变其中一个不会影响另一个。
# 切片
lst = [1, 2, 3, 4]
lc = lst[:]
print(id(lst) == id(lc)) # false
# 对象的copy
lc = lst.copy()
print(id(lst) == id(lc)) # false
# copy模块的copy
from copy import copy
lc = copy(lst)
print(id(lst) == id(lc)) # false
浅拷贝:创建新的对象,其id值和原对象id值不同,如果内部元素有可变对象(不可哈希的),改变可变对象的值会影响另一个。
from copy import copy
lst = [[5, 6], 2, 3, 4]
lc = copy(lst)
print(id(lst) == id(lc)) # false
lc[0].append(999)
print('lst:{}'.format(lst)) # lst:[[5, 6, 999], 2, 3, 4]
print('lc:{}'.format(lc)) # lc:[[5, 6, 999], 2, 3, 4]
但是,如果把内部的可变对象替换为新的对象,而不是修改其值,则不会影响原对象。
st = [[5, 6], 2, 3, 4]
# 对象的copy
lc = copy(lst)
lc[0] = [0,1]
print(id(lst) == id(lc)) # false
print('lst:{}'.format(lst)) # lst:[[5, 6], 2, 3, 4]
print('lc:{}'.format(lc)) # lc:[[0, 1], 2, 3, 4]
深拷贝:创建新的对象 ,其id值和原对象id值不同,改变其中一个不会影响另一个。
from copy import deepcopy
lst = [[5, 6], 2, 3, 4]
lc = deepcopy(lst)
lc[0].append(999)
print(id(lst) == id(lc)) # false
print('lst:{}'.format(lst)) # lst:[[5, 6], 2, 3, 4]
print('lc:{}'.format(lc)) # lc:[[5, 6, 999], 2, 3, 4]
二,字符串
字符串是不可变对象,赋值,浅拷贝,深拷贝操作不会改变id值。
s = 'hello'
t = s
print(t is s) # true
t += 'L' # t指向新的对象
print(s, t) # hello helloL
print(t is s) # false
三、元组
元组中不含可变对象时,赋值,浅拷贝,深拷贝操作不会改变id值。
a = (1, 2, 3)
b = a
print(a is b) # true
b += (999,) # b指向新的对象
print(a, b) # (1, 2, 3) (1, 2, 3, 999)
print(a is b) # false
元组中含有可变对象时,赋值,浅拷贝后的变量修改可变对象的值,会影响原对象。
a = (1, [4,5], 3)
b = a
print(a is b) # true
b[1].append(999)
print(a, b) # (1, [4, 5, 999], 3) (1, [4, 5, 999], 3)
print(a is b) # true
元组中含有可变对象时,深拷贝后的变量修改可变对象的值,不会影响原对象。
from copy import copy,deepcopy
a = (1, [4,5], 3)
b = deepcopy(a) # false
print(a is b)
b[1].append(999)
print(a, b) # (1, [4, 5], 3) (1, [4, 5, 999], 3)
print(a is b) # false
四、集合
赋值操作不会改变id值,其中一个改变会影响另一个。
a = {1, 2, 3}
b = a
print(a is b) # true
b.add(999)
print(a, b) # {1, 2, 3, 999} {1, 2, 3, 999}
print(a is b) # true
浅拷贝会改变id值,其中一个改变不会影响另一个。
from copy import copy
a = {1, 2, 3}
b = copy(a)
print(a is b) # false
b.add(999)
print(a, b) # {1, 2, 3} {1, 2, 3, 999}
print(a is b) # false
集合中的元素都是可哈希的,列表不可哈希,所以集合中不能有列表。
五、字典
赋值操作不会改变id, 其中一个改变会影响另一个。
a = {'a': 1, 'b': 2}
b = a
print(a is b) # true
b['a'] += 1
print(a, b) # {'a': 2, 'b': 2} {'a': 2, 'b': 2}
print(a is b) # true
浅拷贝会改变id值,其中一个改变不会影响另一个。
a = {'a': 1, 'b': 2}
b = a.copy()
print(a is b) # false
b['a'] += 1
print(a, b) # {'a': 1, 'b': 2} {'a': 2, 'b': 2}
print(a is b) # false
但是 如果键对应的值中有可变对象,改变可变对象的值会影响原对象。
a = {'a': [4, 5], 'b': 2}
b = a.copy()
print(a is b) # false
b['a'].append(1)
print(a, b) # {'a': [4, 5, 1], 'b': 2} {'a': [4, 5, 1], 'b': 2}
print(a is b) # false
深拷贝:创建新的对象 ,其id值和原对象id值不同,改变其中一个不会影响另一个。
from copy import deepcopy
a = {'a': [4, 5], 'b': 2}
b = deepcopy(a)
print(a is b) # false
b['a'].append(1)
print(a, b) # {'a': [4, 5], 'b': 2} {'a': [4, 5, 1], 'b': 2}
print(a is b) # false
总结:不可变类型对象,没有拷贝的说法,即使使用深拷贝,查看id值也是一样的,如果对其重新赋值,新的对象会替换掉旧的对象。
一句话就是,不可变类型,不管是深拷贝还是浅拷贝,地址值和拷贝后的值都是一样的。
176

被折叠的 条评论
为什么被折叠?



