可变类型和不可变类型
# 可变和不可变数据类型
# 可变类型:值改变,id不变,证明修改的是内存中的原值。
# 不可变类型:值改变,id也改变,证明是产生的新值
# int 是不可变类型
a = 10
print(id(a)) # 4337951280
a = 20
print(id(a)) # 4337951600
# float 是不可变类型
b = 3.14
# print(id(b)) # 4371068592
b = 5.20
# print(id(b)) # 4371068560
# string 是不可变类型
c = 'hello'
# print(id(c)) # 4298447344
c = 'world'
# print(id(c)) # 4298447408
# 小结: int、float、string都被设计为了一个不可分割的整体,不能够被改变。
# list 是可变类型
x = ['1','2','3']
print(id(x)) # 4337755456
x[0] = 'hello' # 单独修改列表中的某个值。
print(x)
print(id(x)) # 4337755456
# dict 是可变类型
dic = {'name':'x1ong','age' :'17','addr' : 'China'}
print(id(dict)) # 4307849920
dic['name'] = 'Lxx' # 单独修改name,key对应的值
print(id(dic)) # 4307849920
深浅copy
引入
定义如下list1列表:
list1 = [
'x1ong',
'17',
['hello','world']
]
他们在内存中的对应关系:

列表在内存中的对应关系大概是:变量名list1存放在栈区中,而值则存放在堆区。栈区存放了变量名与值的内存地址即0xffff0090。而栈区的变量list1,指向了堆区(值)的内存地址。堆区在记录列表的时候。下标对应每一个列表值的内存地址。
如果我们的代码,在原有的基础上增加变量list2。如下:
list2 = list1 # 将变量list1的值赋值给list2变量
print(list2)
那么,他们再内存中的对应关系则是:

变量list1和变量list2,指向同一个内存地址,如果list1发生改变,那么list2也会跟着改变。
list1 = [
'x1ong',
'17',
['hello','world']
]
list1[0] = 'Xxx'
print(list1) # ['Xxx', '17', ['hello', 'world']]
print(list2) # ['Xxx', '17', ['hello', 'world']]
在内存中的变化则为:

列表中的下标0与0xffff6600解除绑定,与0xffff5530绑定。
需求
- copy一下原列表产生一个新列表
- 想让两个列表完全独立,针对的是写独立,而不是读独立。
如何copy列表?
浅copy
如果你想要copy一个列表,并且让新列表与原列表的修改完全隔开(修改原列表不影响新列表)
并且要copy的列表中不存在可变数据类型,那么我们就可以使用浅copy。
list1 = [
'x1ong',
'17',
['hello','world']
]
# 实验1: 对于不可变类型的重新赋值,都是产生了新值,让原列表的地址索引指向了新的内存地址,并不会印象新列表。
list3 = list1.copy() # 使用copy()函数将list1变量copy一份赋值给list3变量
list1[0] = 'Xxx'
list1[1] = '十八'
list1[2] = '你好世界'
print(list1) # ['XXX', '十八', '123']
print(list3) # ['x1ong', '17', ['hello', 'world']]
在内存中是这样的:

可以发现,由于将list1[2]的值修改为了"你好世界"是一个字符串,所以它是一个不可变类型。所以会给自己开通一个内存地址。不会覆盖原来的地址。因此list3没有被修改。而list3指向的还是'x1ong'和'17'以及列表。所以list3的值没有被改变。
list1 = [
'x1ong',
'17',
['hello','world']
]
# 实验2: 对于可变类型,我们可以改变可变类型中的值,但是内存地址不变。即原列表的索引仍然执行之前的内存地址。于是list3也跟着一起变
list3 = list1.copy() # 使用copy()函数将list1变量copy一份赋值给list3变量
list1[0] = 'Xxx'
list1[1] = '十八'
list1[2][0] = '你好'
list1[2][1] = '世界'
print(list1) # ['XXX', '十八', ['你好', '世界']]
print(list3) # ['x1ong', '17', ['你好', '世界']]
在内存是这样的:

综合以上得知,要想实现copy的新列表与原列表,完全分开,我们就需要有一种可以区分开可变类型和不可变类型的copy机制,这就是深copy。
深copy
如果你想要copy一个列表,并且让新列表与原列表的修改完全隔开(修改原列表不影响新列表),并且要copy的列表中存在可变数据类型,那么我们就可以使用深copy。
import copy
list1 = [
'x1ong',
'17',
['hello','world']
]
list3 = copy.deepcopy(list1)
# 不可变类型 不可变类型 可变类型
print(id(list1[0]),id(list1[1]),id(list1[2]))
print(id(list3[0]),id(list3[1]),id(list3[2]))
'''
以上print的结果
4309317424 4310332464 4303568448
4309317424 4310332464 4310287040
可以发现,前两者内存地址是一样的。而最后一个可变类型,他们两者的内存地址是不一致的
'''
list1[0] = 'XXX'
list1[1] = '十八'
list1[2][0] = '你好'
list1[2][1] = '世界'
print(list1) # ['XXX', '十八', ['你好', '世界']]
print(list3) # ['x1ong', '17', ['hello', 'world']]
在内存中是这样的:

声明:本文章所整理学习的知识全部由Egon老师传授。
Egon老师知乎首页:https://www.zhihu.com/people/xiaoyuanqujing
本文作者为blog,转载请注明。