python深复制与浅复制_python3浅拷贝与深拷贝的区别和理解

文/阿敏其人

本文出自“阿敏其人”简书博客,转载请取得本人同意。

首先,我们知道Python3中,有6个标准的数据类型,他们又分为可变和不可变。

不可变数据(3个):

Number(数字)

String(字符串)

Tuple(元组)

可变数据(3个):

List(列表)

Dictionary(字典)

Set(集合)

浅拷贝和深度拷贝 总结

浅拷贝

copy模块里面的copy方法实现

1、对于 不可 变类型 Number String Tuple,浅复制仅仅是地址指向,不会开辟新空间。

2、对于 可 变类型 List、Dictionary、Set,浅复制会开辟新的空间地址(仅仅是最顶层开辟了新的空间,里层的元素地址还是一样的),进行浅拷贝

3、浅拷贝后,改变原始对象中为可变类型的元素的值,会同时影响拷贝对象的;改变原始对象中为不可变类型的元素的值,只有原始类型受影响。(操作拷贝对象对原始对象的也是同理)

深拷贝

copy模块里面的deepcopy方法实现

1、浅拷贝,除了顶层拷贝,还对子元素也进行了拷贝(本质上递归浅拷贝)

2、经过深拷贝后,原始对象和拷贝对象所有的元素地址都没有相同的了

浅拷贝

1、对于 不可 变类型 Number String Tuple,浅复制仅仅是地址指向,不会开辟新空间。

2、对于 可 变类型 List、Dictionary、Set,浅复制会开辟新的空间地址(仅仅是最顶层开辟了新的空间,里层的元素地址还是一样的),进行浅拷贝

3、浅拷贝后,改变原始对象中为可变类型的元素的值,会同时影响拷贝对象的;改变原始对象中为不可变类型的元素的值,只有原始类型受影响。 (操作拷贝对象对原始对象的也是同理)

可变类型和不可变类型在浅拷贝中的区别

import copy

# 不可变类型 Number String Tuple

print("对于不可 变类型 Number String Tuple,浅复制仅仅是地址指向,不会开辟新空间拷贝值")

num1 = 17

num2 = copy.copy(num1)

print("num1:" + str(id(num1)))

print("num2:" + str(id(num1)))

# num1和num2的地址都相同

str1 = "hello"

str2 = copy.copy(str1)

print("str1:" + str(id(str1)))

print("str2:" + str(id(str2)))

# str1和str2的地址都相同

tup1 = (18, "tom")

tup2 = copy.copy(tup1)

print("tup1:" + str(id(tup1)))

print("tup2:" + str(id(tup2)))

# tup1和tup2的地址都相同

print("="*20)

print("对于可变类型 List、Dictionary、Set,浅复制会开辟新的空间地址(仅仅是最顶层开辟了新的空间),进行浅拷贝")

list1 = [11,12]

list2 = copy.copy(list1)

print("list1:" + str(id(list1)))

print("list2:" + str(id(list2)))

# list1和list2的地址不相同

dic1 = [11,12,"hi"]

dic2 = copy.copy(dic1)

print("dic1:" + str(id(dic1)))

print("dic2:" + str(id(dic2)))

# dic1和dic2的地址不相同

set1 = {"AA","BB"}

set2 = copy.copy(set1)

print("set1:" + str(id(set1)))

print("set2:" + str(id(set2)))

# set1和set2的地址不相同

.

.

输出:

对于不可 变类型 Number String Tuple,浅复制仅仅是地址指向,不会开辟新空间拷贝值

num1:4449693616

num2:4449693616

str1:4452098488

str2:4452098488

tup1:4451942472

tup2:4451942472

====================

对于可变类型 List、Dictionary、Set,浅复制会开辟新的空间地址,进行浅拷贝

list1:4456844424

list2:4452360136

dic1:4452358856

dic2:4456844744

set1:4452279016

set2:4452279464

对list进浅拷贝,对可变类型和不可变类型修改后的影响。

import copy

l1 = [11, 12]

l2 = [21, 22]

num = 555

allOne = [l1, l2,num]

# 浅拷贝,创建出一个对象,并把旧对象元素的 引用地址 拷贝到新对象当中。

# 也就是说,两个对象里面的元素通过浅拷贝指向的还是同一个地址

allOne2 = copy.copy(allOne)

l1[0] = 16 # 此处修改,会使得 allOne 和 allOne2的第0个元素的值都发生改变,因为l1是List,是可变对象

allOne[2] = 666 # 此处修改,只会allOne的num的值,因为不可变对象一旦重新复制,地址就会发生改变。(不可变嘛)

num = 777 # 此处不会改变 allOne 和 allOne2的值,因为相当于 777 复制给一个全新的地址,这个num跟其他num已经没关系了

print(allOne)

print(allOne2)

print("id allOne:"+str(id(allOne)))

print("id allOne[0]:"+str(id(allOne[0])))

print("id allOne[1]:"+str(id(allOne[1])))

print("id allOne[2]:"+str(id(allOne[2])))

print("===")

print("id allOne2:"+str(id(allOne2)))

print("id allOne2[0]:"+str(id(allOne2[0])))

print("id allOne2[1]:"+str(id(allOne2[1])))

print("id allOne2[2]:"+str(id(allOne2[2])))

.

.

打印输出

[[16, 12], [21, 22], 666]

[[16, 12], [21, 22], 555]

id allOne:4467341640

id allOne[0]:4471819912

id allOne[1]:4467342920

id allOne[2]:4466847696

===

id allOne2:4471820232

id allOne2[0]:4471819912

id allOne2[1]:4467342920

id allOne2[2]:4466081744

可以看出:

改动allOne中的可变类型,会影响allOne2,改变allOne2同理影响allOne。

改动allOne2中的不可变类型,只有allOne2自身会改变,allOne不受影响。

(List是可变类型)

.

.

对于不可变类型被修改后造成的影响,我们用一个更加简单的例子便可更好理解:

num = 123

print(str(id(num)))

num = 666

print(str(id(num)))

.

.

console:

4348603632

4350009296

几乎可以说,Python 没有"变量",我们平时所说的变量其实只是"标签",是引用。

关于 = 符号,可以参考 python基础(5):深入理解 python 中的赋值、引用、拷贝、作用域

深拷贝

1、浅拷贝,除了顶层拷贝,还对子元素也进行了拷贝(本质上递归浅拷贝)

2、经过深拷贝后,原始对象和拷贝对象所有的子元素地址都是独立的了

3、可以用分片表达式进行深拷贝

4、字典的copy方法可以拷贝一个字典

深拷贝对6种基本类型的影响

我们对3种可变类型3种不可变类型进行深拷贝。

结果发现,和浅拷贝几乎一致。

其实这也好理解,因为的深拷贝对比浅拷贝,强调的是 递归,强调的是资源素。

对了顶层的操作,深浅拷贝无异。

import copy

# 不可变类型 Number String Tuple

print("对于不可 变类型 Number String Tuple,深复制依然是地址指向,不会开辟新空间拷贝值")

num1 = 17

num2 = copy.deepcopy(num1) # 深拷贝

print("num1:" + str(id(num1)))

print("num2:" + str(id(num1)))

# num1和num2的地址都相同

str1 = "hello"

str2 = copy.deepcopy(str1) # 深拷贝

print("str1:" + str(id(str1)))

print("str2:" + str(id(str2)))

# str1和str2的地址都相同

tup1 = (18, "tom")

tup2 = copy.deepcopy(tup1) # 深拷贝

print("tup1:" + str(id(tup1)))

print("tup2:" + str(id(tup2)))

# tup1和tup2的地址都相同

print("="*20)

print("对于可变类型 List、Dictionary、Set,深拷贝会开辟新的空间地址,进行拷贝")

list1 = [11,12]

list2 = copy.deepcopy(list1) # 深拷贝

print("list1:" + str(id(list1)))

print("list2:" + str(id(list2)))

# list1和list2的地址不相同

dic1 = [11,12,"hi"]

dic2 = copy.deepcopy(dic1) # 深拷贝

print("dic1:" + str(id(dic1)))

print("dic2:" + str(id(dic2)))

# dic1和dic2的地址不相同

set1 = {"AA","BB"}

set2 = copy.deepcopy(set1) # 深拷贝

print("set1:" + str(id(set1)))

print("set2:" + str(id(set2)))

# set1和set2的地址不相同

深拷贝的会对子元素也进行拷贝

import copy

l1 = [11, 12]

l2 = [21, 22]

num = 555

allOne = [l1, l2,num]

# 浅拷贝,除了顶层拷贝,还对子元素也进行了拷贝(本质上递归浅拷贝)

# 经过深拷贝后,原始对象和拷贝对象所有的元素地址都没有相同的了

allOne2 = copy.deepcopy(allOne) # copy.deepcopy 深拷贝

allOne[1] = [113,114]

allOne2[2] = [227,228]

print(allOne)

print(allOne2)

print("id allOne:"+str(id(allOne)))

print("id allOne[0]:"+str(id(allOne[0])))

print("id allOne[1]:"+str(id(allOne[1])))

print("id allOne[2]:"+str(id(allOne[2])))

print("===")

print("id allOne2:"+str(id(allOne2)))

print("id allOne2[0]:"+str(id(allOne2[0])))

print("id allOne2[1]:"+str(id(allOne2[1])))

print("id allOne2[2]:"+str(id(allOne2[2])))

.

.

console

[[11, 12], [113, 114], 555]

[[11, 12], [21, 22], [227, 228]]

id allOne:4549589640

id allOne[0]:4554067720

id allOne[1]:4554067848

id allOne[2]:4548329424

===

id allOne2:4554067912

id allOne2[0]:4554067784

id allOne2[1]:4554067592

id allOne2[2]:4554100808

本例是跟浅拷贝做对比的。

在之前的浅拷贝中,子元素是不会开辟新空间做拷贝的。

而在深拷贝中,子元素也进行了拷贝。

其他拷贝方式

除了copy模块的中的copy和deepcopy,还有其他自带的方式可实现拷贝。

1、分片表达式进行浅拷贝

2、字典的copy方法可以拷贝一个字典

分片表达式拷贝

l1 = [11, 12]

l2 = [21, 22]

num = 555

orgi = [l1, l2, num]

nList = orgi[:]

print("orgi:"+str(id(orgi)))

print("orgi[0]:"+str(id(orgi[0])))

print("orgi[1]:"+str(id(orgi[1])))

print("orgi[2]:"+str(id(orgi[2])))

print("*"*30)

print("nList:"+str(id(nList)))

print("nList[0]:"+str(id(nList[0])))

print("nList[1]:"+str(id(nList[1])))

print("nList[2]:"+str(id(nList[2])))

用分片表达式进行的拷贝,是浅拷贝。

字典自带的copy方法可实现深拷贝

dic = {"key": "hello", "num": 18}

dic2 = dic.copy()

dic["key"] = "one"

dic2["key"] = "two"

print(dic)

print("dic:" + str(id(dic)))

print(dic2)

print("dic2:" + str(id(dic2)))

console:

{'key': 'one', 'num': 18}

dic:4382946792

{'key': 'two', 'num': 18}

dic2:4382946864

本文完,谢谢阅读。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值