复制代码

深拷贝和浅拷贝的区别

赋值

在我们开始讨论浅拷贝和深拷贝的区别之前,首先我们必须清楚什么是赋值?

在Python中,所谓的赋值实际上就是对象引用的传递而已,当创建一个对象的时候,再赋值给另外一个变量的时候,并不是赋值给另一个变量。而是把这个变量在地址空间的id地址值传递给另一个变量,简单的说就是拷贝了这个对象的引用。看图片,可能比较容易理解。

从图中,我们很容易的看到,a和b两个变量在地址空间中是一样。后来,我们又给a增加一个值89之后,a和b两个地址值还是一样。

浅拷贝

 

浅拷贝是对一个对象父级(外层)的拷贝,并不会拷贝子级(内部)。使用浅拷贝的时候,分为两种情况。
第一种,如果最外层的数据类型是可变的,比如说列表,字典等,浅拷贝会开启新的地址空间去存放。
第二种,如果最外层的数据类型是不可变的,比如元组,字符串等,浅拷贝对象的时候,还是引用对象的地址空间。

 

 

  • 看图,我们就明白的看出,c的最外层是[a,b],可变数据类型,d在浅拷贝的时候,也直接把最外层拿过来。只拷贝最外层,而里面却没有拿到。
  • 1、对于 不可 变类型 Number String Tuple,浅复制仅仅是地址指向,不会开辟新空间。
  • 2、对于 变类型 List、Dictionary、Set,浅复制会开辟新的空间地址(仅仅是最顶层开辟了新的空间,里层的元素地址还是一样的),进行浅拷贝
  • 3、浅拷贝后,改变原始对象中为可变类型的元素的值,会同时影响拷贝对象的;改变原始对象中为不可变类型的元素的值,只有原始类型受影响。 (操作拷贝对象对原始对象的也是同理)

深拷贝

  • 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

 

posted @ 2021-11-29 10:41  怪~咖  阅读(339)  评论(0编辑  收藏  举报
复制代码