11. 拷贝详解

92 阅读5分钟

在前面的章节里,总说到一个方法,叫copy,而且也都解释了,都是浅拷贝,那什么是浅拷贝什么是深拷贝呢?

一,前置

1,id(object)

作用:返回object的唯一标识符(内存地址)

2,copy模块

通过导入copy模块,然后可以使用已封装好的浅拷贝函数copy()和深拷贝函数deepcopy()

二,赋值

在讲变量的定义时,有说过,在定义变量的过程中,其实是开启了一块内存空间存放数据,并建立此内存空间与变量名的关联关系 像如下,使a = 888,再通过内置函数id()获取变量地址时,返回的其实是888存放的内存空间的地址

a = 888
print(id(a))

输出为

1974774331216

另外,对于整数数据,在[-5, 256]之间的整数,如果数值相等,地址其实也就相同,这叫小整数对象池(需要再交互式窗口更明显,如终端执行,jupyter等等)

a = 255
print(id(a))
print(id(255))

a = 257
print(id(a))
print(id(257))

输出为

1974692178288
1974692178288
1974774331312
1974774330928

一个值,也能被多个变量名引用,但当引用次数为0时,那么会将此值存放的内存空间释放

a = 999
b = 999
c = a
print(id(a))
print(id(b))
print(id(c))

输出为

1974774332944
1974774331600
1974774332944

当一个可变类型的数据被多个变量名引用时,如果对该数据修改,所有引用都会改变

a = [999]
b = [999]
c = a
print(id(a))
print(id(b))
print(id(c))
print('--------------------------')
a.append(2)
print(a)
print(b)
print(c)
print(id(a))
print(id(b))
print(id(c))

输出为

1974774408064
1974774407872
1974774408064
--------------------------
[999, 2]
[999]
[999, 2]
1974774408064
1974774407872
1974774408064

三,浅拷贝&深拷贝

对于不可变数据类型来说,两种类型的拷贝都等同于赋值,都是拉了个指向同一地址的引用关系;而对于可变数据类型来说,浅拷贝和深拷贝的区别就是深拷贝会对包含的所有可变数据类型都会重新开辟空间存储,而浅拷贝不是。

1,浅拷贝-不可变数据类型

等效于赋值,没有拷贝的意义

import copy

a = "999"
b = copy.copy(a)
print(a)
print(b)
print(id(a))
print(id(b))
print('--------------------------')
a =  "888"
print(a)
print(b)
print(id(a))
print(id(b))

输出为

999
999
1974775182512
1974775182512
--------------------------
888
999
1974775184880
1974775182512

从上例中可以看出,b是浅拷贝的a从而建立起与999的关联关系,虽然a重新赋值了888,b和999的引用关系是没有发生改变的

2,浅拷贝-可变数据类型

如果浅拷贝的是可变数据类型,那么浅拷贝会重新开辟一个数据空间来存放该对象,只是对象里面的各元素(无论是可变还是不可变)还是和以前一样的引用关系,如下

import copy

a = [1, 2, 3, 4 , 'a',[]]
b = copy.copy(a)

print(a)
print(b)
print(id(a))
print(id(b))
print(id(a[0]))
print(id(b[0]))
print(id(a[2]))
print(id(b[2]))
print(id(a[-1]))
print(id(b[-1]))

输出为

[1, 2, 3, 4, 'a', []]
[1, 2, 3, 4, 'a', []]
1974775183296
1974774416960
1974691981616
1974691981616
1974691981680
1974691981680
1974774407616
1974774407616

可看出列表里的元素的地址是一样的,只是列表本身的地址不一样了

3,深拷贝-可变类型

等同于赋值,没有拷贝的意义

import copy

a = "999"
b = copy.deepcopy(a)
print(a)
print(b)
print(id(a))
print(id(b))

输出为

999
999
1974774322416
1974774322416

4,深拷贝-不可变类型

和浅拷贝的区别就是包含的元素若为不可变类型,则是重新开辟空间去储存

import copy

a = [1, 2, 3, 4 , 'a',[]]
b = copy.deepcopy(a)

print(a)
print(b)
print(id(a))
print(id(b))
print(id(a[0]))
print(id(b[0]))
print(id(a[2]))
print(id(b[2]))
print(id(a[-1]))
print(id(b[-1]))

输出为

[1, 2, 3, 4, 'a', []]
[1, 2, 3, 4, 'a', []]
1974775219584
1974774399808
1974691981616
1974691981616
1974691981680
1974691981680
1974775223168
1974774084416