Python可变不可变数据类型
首先,Python的数据类型按照“值“改变的时候内存地址是否变化来区分是否是可变数据类型还是不可变数据类型。
不可变数据类型:就是当你定一个变量的时候,一旦修改了他的值,那么他在内存中的地址就会发生改变,是一一对应的,所以就可以哈希。不可变的数据类型有:string,number,布尔,元祖(不可变)
a = 123
print(id(a)) # 140726960160832
a = 1
print(id(a)) # 140726960156928
可变数据类型正好相反,在改变值的情况下,是不会发生内存地址的变化的,例如列表,字典,集合等
Python一切皆对象,所以拷贝复制就是在拷贝对象:
第一种复制:直接赋值 =
修改不可变数据类型的变量,没有意义,这里只说可变数据类型的拷贝。
可以看出 等号复制,就是一个引用,就是给这个地址起了另一个名字,就像一个人可以有两个名字一样,当你修改其中任意一个变量的值,其他变量的值都会跟着改变。且在内存中的地址永远不变。所以等号复制不是拷贝,他还是他。
#工作中千万不要这样去使用可变的数据类型,会出现很大的bug的。
第二种复制:浅拷贝
还是只说可变的数据类型,不可变的没有意义。
代码中一旦有了copy(),那么内存才会给你分配一个新的地址,这样的话,首先第二个变量在内存中地址肯定是变了的。也就是说你改变另一个变量的值已经不会影响另一个变量的值了。
其内层原理是,比如一个列表 a = [1,2,3] 这里面的元素的数据类型都是不可变的,所以当拷贝的时候,将里面的一个个元素的地址都给拷贝过来了,且这些都是不可变数据类型,一旦值改变,就会导致内存地址的改变,所以他的浅拷贝就是深拷贝,完完全全复制了一个新的对象出来,你所做的所有修改操作,不会影响原来的对象。
这就引来一个新的问题:第三种复制:深拷贝
假如我的列表是a = [1,2,3,['a','b']], 或者a = [1,2,3,{'a':'b'}],也就是 一个对象中嵌套有一个可变数据类型,那么只用copy(),拷贝的还是这个数据类型的地址,无论你怎么修改他的值,内存地址是不会变的,所以会影响到之前的变量,但是不可变数据类型不受影响。也就是上述列表中的1,2,3,修改了,是不会修改之前的变量的。
这里给出几个测试结果,看了就会明白:
import copy
a = [1, 2, 3, 4, ['a', 'b']] #原始对象
b = a #赋值,传对象的引用
c = copy.copy(a) #对象拷贝,浅拷贝
d = copy.deepcopy(a) #对象拷贝,深拷贝
a.append(5) #修改对象a
a[4].append('c') #修改对象a中的['a', 'b']数组对象
print( 'a = ', a )
print( 'b = ', b )
print( 'c = ', c )
print( 'd = ', d )
以上结果为:
('a = ', [1, 2, 3, 4, ['a', 'b', 'c'], 5])
('b = ', [1, 2, 3, 4, ['a', 'b', 'c'], 5]) # 只是起了个别名而已
('c = ', [1, 2, 3, 4, ['a', 'b', 'c']]) # 可变数据类型的地址不变,所以此处内存指向的值发生变化,
# 他也会跟着变化
('d = ', [1, 2, 3, 4, ['a', 'b']]) # 完完全全的一个新的对象