python之深浅copy

文章目录

  • python之深浅copy
    • 引入
      • 1.为什么要使用深浅拷贝
    • 一.赋值运算
      • 1.赋值运算原理
      • 2.示例
      • 3.总结
    • 二、拷贝
    • 三.浅拷贝
        • 什么是浅拷贝?
      • 1.浅拷贝原理
        • 创建浅拷贝的几种方式:
      • 2.示例
      • 3.总结
    • 四.深拷贝
        • 什么是深拷贝?
      • 1.深拷贝原理
        • 创建深拷贝:
      • 2.示例
      • 3.总结

引入

1.为什么要使用深浅拷贝

  • 涉及到容器类型的修改操作时,想要保留原来的数据或修改后的数据,这是就需要使用到深浅拷贝来进行操作了

  • 以下使用列表list1 = [ "str", 123, [111,222]]拷贝来进行实验

一.赋值运算

1.赋值运算原理

  • 赋值操作是指源列表与新列表指向的是同一个内存地址,无论是通过新变量名还是原变量名改变变量值内的元素,二者所对应的变量值都会改变(因为是同一个)。
  • list2 = list1

2.示例

?创建一个列表,包含字符串,整形和列表(可变),并将其赋值给另一个变量名
list1 = ["str", 123, [111,222]]
list2 = list1?查看两个列表的"id",可以发现"id"不变,是同一个
print(id(list1))  #2248006456392
print(id(list2))  #2248006456392
print(id(list1[0]),id(list1[1]),id(list1[2]))
# 2248006252720 140725163491392 2248006455880
print(id(list2[0]),id(list2[1]),id(list2[2]))
# 2248006252720 140725163491392 2248006455880?当改变"list1"内的第一或者第二个元素(不可变元素)
list1[0] = "aaa"
print(list1[0],id(list1[0]))
# aaa 2248007720496
print(list2[0],id(list2[0]))
# aaa 2248007720496
?发现"list1"改变的值的内存地址已经变化了,说明是产生的新值,与原来的"str"取消了对应
?而"list2"中的值和"id"也跟着改变?当改变子列表里面的值时
list1[2][0] = 333
print(list1[2],id(list1[2]))
# [333, 222] 2248006455880
print(list2[2],id(list2[2]))
# [333, 222] 2248006455880
?我们发现两个列表的值都发生了改变,但子列表的"id"还都是不变的

3.总结

  • 赋值操作列表与新列表都是指向同一内存地址,所以他们都完全一样。
  • 2个列表中,只要有一个人的列表中的索引所对应的值的内存地址改变,则都改变
  • 也就是把源列表容器的内存地址完完整整的多绑定一份交给新列表

二、拷贝

拷贝是音译的词,是从copy这个英文单词音译过来的,copy其实就是复制一份。

在Python中,列表的内存地址存放的是元素的索引与元素内存地址的对应关系。

三.浅拷贝

什么是浅拷贝?

浅拷贝指仅拷贝对象的第一层,是在内存中重新开辟了一个空间存放索引与元素内存地址的对应关系。

对于原列表内的不可变数据类型,浅拷贝指向的内存地址和原对象指向的内存地址是同一个。当原对象第一层的元素改变,指向一个新的内存地址,而浅拷贝的内存地址指向的还是原内存地址。当原对象的深层元素改变,指向一个新的内存地址,浅拷贝的内存地址指向也会跟着变。

对于列表内的可变数据类型,浅拷贝指向的内存地址和原对象指向的内存地址是也同一个。但对**子列表内的元素,并没有指向列表内元素的内存地址。当子列表内的元素改变,子列表的内存地址并没有变,子列表内的元素内存地址改变。**浅拷贝指向子列表的内存地址不变,原子列表内存元素地址改变,浅拷贝指向的子列表元素内存地址也一起改变。

结论:当列表内第一层不可变数据类型的元素改变,浅拷贝的元素不会改变(还是指向原内存地址)。当列表内可变数据类型的子元素改变,浅拷贝的可变数据类型内的子元素也会跟着一起改变(仅指向可变数据类型本身)。

1.浅拷贝原理

  • 把源列表第一层的内存地址不加区分(不区分是可变还是不可变类型)的完全copy给一份新列表
  • 对源列表copy之后, 产生的新列表的内存地址发生了改变, 它们不再是同一个列表
  • 但是新列表与源列表中的可变和不可变类型的值在修改之前都是指向同一个值
  • list2 = list1.copy()

创建浅拷贝的几种方式:

  • 列表内置方法
l1 = [1, 'b', 'c', [10, 20, 30]]
l2 = copy.copy((l1))
  • 完全切片
l1 = [1, 'b', 'c', [10, 20, 30]]
l2 = l1[:]
  • copy模块
import copy
l1 = [1, 'b', 'c', [10, 20, 30]]
l2 = copy.copy(l1)

2.示例

?创建一个列表,包含字符串,整形和列表(可变),并将其浅拷贝
list1 = ["str", 123, [111,222]]
list2 = list1.copy()?查看两个列表的"id",可见是产生了新的一个内存地址
print(id(list1))  #2243511014472
print(id(list2))  #2243541368584
print(id(list1[0]),id(list1[1]),id(list1[2]))
# 2243510810800 140725163491392 2243511013960
print(id(list2[0]),id(list2[1]),id(list2[2]))
# 2243510810800 140725163491392 2243511013960
?复制过来的元素内存地址都是同一个,说明复制的只是变量名与内存地址的对应关系,指向的是同一个内存地址?当改变"list1"内的第一或者第二个元素(不可变元素)
list1[0] = "aaa"
print(list1[0],id(list1[0]))
# aaa 2240322768432
print(list2[0],id(list2[0]))
# str 2243510810800
?发现"list1"改变的值的内存地址已经变化了,说明是产生的新值,与原来的"str"取消了对应
?而"list2"中的值和"id"都没变,说明还是原来的对应关系?当改变子列表里面的值时
list1[2][0] = 333
print(list1[2],id(list1[2]))
# [333, 222] 2243511013960
print(list2[2],id(list2[2]))
# [333, 222] 2243511013960
?我们发现两个列表的值都发生了改变,但子列表的"id"还都是不变的

3.总结

  • 对源列表中不可变类型的值进行修改以后,对于不可变类型的值,都是产生新值,让源列表的索引指向新的内存地址,并不会影响新列表
  • 对源列表中可变类型的值进行修改以后,对于可变类型,我们可以改变类型中包含的值,但这个可变容器本身内存地址不变
  • 即新列表的索引仍然指向原来的内存地址,于是新列表也跟着受影响。
  • 对于浅copy来说,只是在内存中重新创建了开辟了一个空间存放一个新列表,但是新列表中的元素与原列表中的元素是公用的。
  • 浅copy:列表、字典嵌套的数据类型是同一个。

四.深拷贝

什么是深拷贝?

深拷贝指拷贝对象的每一层,每一层都是在内存中重新开辟了一个空间存放一个新列表。

对于原列表内的每一层不可变数据类型,包括原列表内的子列表内的不可变数据类型,深拷贝指向的内存地址和原列表指向的内存地址是同一个。当原对象的值改变,会指向一个新的内存地址。而深拷贝的内存地址指向的还是原内存地址。

对于列表内的可变数据类型,深拷贝会重新申请一块内存空间,存放原列表内元素索引与元素id的对应关系。

结论:当列表内每一层不可变数据类型的元素改变,深拷贝内的元素都不会改变(指向的是原内存地址)。当列表内可变数据类型(列表本身,而非列表内的不可变类型元素)改变,深拷贝还是不变(可变类型深拷贝是重新申请了内存空间)。

1.深拷贝原理

  • 深拷贝对容器类型中的每一层得数据加以区分 (对可变不可变类型区分对待)
  • 针对不可变类型, 拷贝以后任然还是用原来值的内存地址, 但值一发生改变就会产生新值, 于是与原来的值没有任何关联
  • 针对可变类型, 拷贝之后会申请新的内存地址存放, 在新的内存地址中再次区分(可变还是不可变)
  • 再次区分判断后, 于是重复针对不可变类型和针对可变类型所进行的操作, 以此类推
  • import copy,copy.deepcopy(list)

创建深拷贝:

要使用到copy模块。

import copy
l1 = [1, 'b', 'c', [10, 20, 30]]
l2 = copy.deepcopy(l1)

2.示例

?导入模块
import copy
?创建一个列表,包含字符串,整形和列表(可变),并将其深拷贝
list1 = ["str", 123, [111,222]]
list2 = copy.deepcopy(list1)?查看两个列表的"id",可见是产生了新的一个内存地址
print(id(list1))  #2655395993736
print(id(list2))  #2655397313096
print(id(list1[0]),id(list1[1]),id(list1[2]))
# 2655393364144 140725163491392 2655397312904
print(id(list2[0]),id(list2[1]),id(list2[2]))
# 2655393364144 140725163491392 2655397313672
?针对不可变类型, 拷贝以后任然还是用原来值的内存地址
?针对可变类型, 拷贝之后会申请新的内存地址存放?当改变"list1"内的第一或者第二个元素(不可变元素)
list1[0] = "aaa"
print(list1[0],id(list1[0]))
# aaa 2655394824496
print(list2[0],id(list2[0]))
# str 2655393364144
?发现"list1"改变的值的内存地址已经变化了,说明是产生的新值,与原来的"str"取消了对应
?而"list2"中的值和"id"都没变,说明""list1"的改变与"list2"无关?当改变子列表里面的值时
list1[2][0] = 333
print(list1[2],id(list1[2]))
# [333, 222] 2655397312904
print(list2[2],id(list2[2]))
# [111, 222] 2655397313672
?我们发现"list1"的变化依然与"list2"无关

3.总结

  • 深拷贝等于是把源列表和新列表完完整整的独立开来互不干扰,
  • 这样就可以保存原数据, 又可以保存操作后的数据
  • 对于深copy来说,列表是在内存中重新创建的,列表中可变的数据类型是重新创建的,列表中的不可变的数据类型是公用的。
  • 深copy:列表、字典嵌套的数据类型不是同一个

相关面试题

l1 = [1, 2, 3, 4, ['淘小欣']]
l2 = l1[::]
l1[-1].append(666)
print(l2)

python之深浅copy相关推荐

  1. day python calss08 深浅copy

    一  join (格式:   . join) 遍历列表把列表中的每一项用指定符号进行拼接.(把列表转成字符串0 # lst = ["汪峰", "吴君如", &q ...

  2. Python基础三--字典,集合,编码,深浅copy,元祖、文件操作

    字典 dict数据类型划分:可变数据类型,不可变数据类型不可变数据类型: 元组,bool值,int,str 可哈希可变数据类型: list,dict,set 不可哈希 dict key :必须是不可变 ...

  3. python怎么设置颜色深浅变化_Python赋值、深浅copy

    Python赋值.深浅copy assignment: 在 Python 中,对象的赋值就是简单的对象引用,这点和 C++不同,如下所示 a = [1, 2, 'hello', ['python', ...

  4. python 的内存回收,及深浅Copy详解

    一.python中的变量及引用 1.1 python中的不可变类型: 数字(num).字符串(str).元组(tuple).布尔值(bool<True,False>) 接下来我们讲完后你就 ...

  5. Python 深浅copy 和文件操作

    深浅copy 1,先看赋值运算. l1 = [1,2,3,['barry','alex']] l2 = l1l1[0] = 111 print(l1) # [111, 2, 3, ['barry', ...

  6. [转载] python创建集合、计算a|b_python之路(集合,深浅copy,基础数据补充)

    参考链接: Python 集合set | symmetric_difference 一.集合:类似列表,元组的存储数据容器,不同点是不可修改,不可重复.无序排列. 1.创建集合: (1).set1 = ...

  7. 乐学python怎么样_铁乐学Python_day07_集合and浅谈深浅copy

    1.[List补充] 在循环一个列表时,最好不要使用元素和索引进行删除操作,一旦删除,索引会随之改变,容易出错. 如果想不出错,可以采用倒着删除的方法,因为倒着删除进行的话,只是后面元素的位置发生了变 ...

  8. python拷贝文件函数_python笔记2小数据池,深浅copy,文件操作及函数初级

    小数据池就是在内存中已经开辟了一些特定的数据,经一些变量名直接指向这个内存,多个变量间公用一个内存的数据. int: -5 ~ 256 范围之内 str: 满足一定得规则的字符串. 小数据池: 1,节 ...

  9. Python深浅copy

    在python里对对象进行拷贝有三个,即赋值,深拷贝,浅拷贝.而对象又分为两种,一种是不可变对象(字符串.元组.数字 ),一种是可变对象(列表.字典).而深浅拷贝有三种情况: 拷贝的是不可变对象,对于 ...

最新文章

  1. 漫画:如何在数组中找到和为 “特定值” 的两个数?
  2. 超越halcon速度的二值图像的腐蚀和膨胀,实现目前最快的半径相关类算法(附核心源码)。...
  3. 中断中是否可以使用信号量?
  4. Rundll32使用技巧
  5. 每天6亿人在看《延禧攻略》?大数据告诉你哪家视频网站VIP值得买(附代码)
  6. 【源码】ListT泛型绑定repeater,以及repeater的交替绑定
  7. 人工智能(12)---中国智能语音业务与应用发展白皮书
  8. AForge.net简介和认识
  9. 原来Android还可以这样通过反射,获取jar包属性及方法
  10. echarts3D环形图(包含点击效果)
  11. 西北工业大学 编译原理实验 minic文法 编译器前端 flex-bison实现 的 debug手记
  12. 车辆VIN码的校验算法
  13. 65W氮化镓Switch底座扩展坞方案
  14. 数字阅读市场陷入两强之争 掌阅能不能守住半壁江山?
  15. cf_332b - Maximum Absurdity
  16. 开发单片机常见的IDE有哪些?
  17. 发票预制和过账冻结与付款冻结的关联
  18. Python的生成器和迭代器
  19. 第7节 蒙卡模拟计算路径依赖型期权价格
  20. 基于FFmpeg+SDL的视频播放器的制作-基础知识

热门文章

  1. cmp 字节 汇编_汇编 常用指令 cmp jmp call ret
  2. 2021-10-26为什么单相短路和两相接地短路 的阻抗Zf的位置不同
  3. bootstrap动态调用select下拉框
  4. 锂电池寿命预测 | Pytorch实现基于Transformer 的锂电池寿命预测(NASA数据集)
  5. oracle tnsnames.ora配置详解
  6. akshare做mfi策略
  7. wxpython下拉选择框_wxPython ComboBox Choice类
  8. 我的世界JAVA版有没有混凝土_我的世界1.12混凝土详解 混凝土合成教程
  9. Robot Framework--05 案例设计之流程与数据分离
  10. Top 10 Unanswered Questions in Geeky Movies