底层剖析Python深浅拷贝

拷贝的用途

  拷贝就是copy,目的在于复制出一份一模一样的数据。使用相同的算法对于产生的数据有多种截然不同的用途时就可以使用copy技术,将copy出的各种副本去做各种不同的操作。

  值得一提的是绝大部分编程语言中对于copy都有深浅拷贝的概念,所以充分的理解本章节的知识也是在为今后学习其他编程语言少走弯路。

  在Python中,除开手动deepcopy(),其他的任何操作都是浅拷贝。

Python = 赋值示例

  好了,废话不多说。直接进入主题,上代码:

  1. >>> # ==== = 赋值示例 ====
  2. >>>
  3. >>> li1 = ["a","b",[1,2]] # 注意存储的数据类型。第一层存储2个不可变类型,1个可变类型小容器(list),第二层存储2个不可变类型
  4. >>> id(li1) # 第一层,查看变量名所指向的列表(第一层容器)的内存地址id号
  5. 2324901133120
  6. >>> id(li1[0]) # 第一层,查看第一层容器中的具体元素内存地址id号
  7. 2324900663472
  8. >>> id(li1[-1]) # 第二层(小容器id号),查看第一层容器中的小容器list的内存地址id号
  9. 2324900812864
  10. >>> li1
  11. ['a', 'b', [1, 2]]
  12. >>> # =============手动分割线=============
  13. >>> li2 = li1
  14. >>> id(li2) # 第一层,查看变量名所指向的列表(第一层容器)的内存地址id号
  15. 2324901133120
  16. >>> id(li2[0]) # 第一层,查看第一层容器中的具体元素内存地址id号
  17. 2324900663472
  18. >>> id(li2[-1]) # 第二层(小容器id号),查看第一层容器中的小容器list的内存地址id号
  19. 2324900812864
  20. >>> li2 # 可以看到 li2 与li1 不管是第一层。还是第二层的内存地址id号都全部一样
  21. ['a', 'b', [1, 2]]
  22. >>>

  尝试修改li1,查看li2的变化:

  1. >>> li1[0] = "x"
  2. >>> li1[-1][-1] = 20
  3. >>> li1
  4. ['x', 'b', [1, 20]]
  5. >>> li2 #可以看到li2随着li1而变化,不管是第一层还是第二层都跟着变化,因为内存引用都全部一样。
  6. ['x', 'b', [1, 20]]
  7. >>>

赋值结论:

  本体            

    1.修改不可变类型数据(如:第一层的str

    2.修改可变数据类型中的数据(如:第二层小容器list中的数据)

对应关系

  拷贝体

    1.不保持原本体中的值,跟随本体变化

    2.不保持原本体中的值,跟随本体变化

底层原理


Python 浅拷贝示例

  浅拷贝,用到list数据类型自带的方法,copy()。我们来看一看会怎么样:

  1. >>> # ==== 浅拷贝示例 ====
  2. >>>
  3. >>> li1 = ["a","b",[1,2]] # 注意存储的数据类型。第一层存储2个不可变类型,1个可变类型小容器(list),第二层存储2个不可变类型
  4. >>> id(li1) # 第一层,查看变量名所指向的列表(第一层容器)的内存地址id号
  5. 3120558308288
  6. >>> id(li1[0]) # 第一层,查看第一层容器中的具体元素内存地址id号
  7. 3120557838512
  8. >>> id(li1[-1]) # 第二层(小容器id号),查看第一层容器中的小容器list的内存地址id号
  9. 3120557987904
  10. >>> li1
  11. ['a', 'b', [1, 2]]
  12. >>> #=============手动分割线=============
  13. >>> li2 = li1.copy()
  14. >>> id(li2) # 第一层,查看变量名所指向的列表(第一层容器)内存地址id号
  15. 3120558308352
  16. >>> id(li2[0]) # 第一层,查看第一层容器中的具体元素内存地址id号
  17. 3120557838512
  18. >>> id(li2[-1]) # 第二层(小容器id号),查看第一层容器中的小容器list的内存地址id号
  19. 3120557987904
  20. >>> li2 # 可以看到 li2 与li1 第一层的内存地址已经发生了变化。只有第二层的内存引用地址一样
  21. ['a', 'b', [1, 2]]
  22. >>>

  尝试修改li1,查看li2的变化:

  1. >>> li1[0] = "x"
  2. >>> li1[-1][-1] = 20
  3. >>> li1
  4. ['x', 'b', [1, 20]]
  5. >>> li2 # li2 仅仅只有第二层小容器list中的值发生了变化。而第一层中的str不可变类型并没有发生变化
  6. ['a', 'b', [1, 20]]
  7. >>>

浅拷贝结论:

  本体            

    1.修改不可变类型数据(如:第一层的str

    2.修改可变数据类型中的数据(如:第二层小容器list中的数据)

对应关系

  拷贝体

    1.保持原本体中的值,不发生变化

    2.不保持原本体中的值,跟随本体变化

底层原理


Python 深拷贝示例

  使用深拷贝需要导入Python的内置库,copy,具体使用方式还是看代码:

  1. >>> # ==== 深拷贝示例 ====
  2. >>>
  3. >>> from copy import deepcopy # deep深度的意思,copy就拷贝。
  4. >>> li1 = ["a","b",[1,2]] # 注意存储的数据类型。第一层存储2个不可变类型,1个可变类型小容器(list),第二层存储2个不可变 类型
  5. >>> id(li1) # 第一层,查看变量名所指向的列表(第一层容器)的内存地址id号
  6. 3120558351168
  7. >>> id(li1[0]) # 第一层,查看第一层容器中的具体元素内存地址id号
  8. 3120557838512
  9. >>> id(li1[-1]) # 第二层(小容器id号),查看第一层容器中的小容器list的内存地址id号
  10. 3120558353280
  11. >>> li1
  12. ['a', 'b', [1, 2]]
  13. >>> #=============手动分割线=============
  14. >>> li2 = deepcopy(li1)
  15. >>> id(li2) # 第一层,查看变量名所指向的列表(第一层容器)内存地址id号
  16. 3120558308288
  17. >>> id(li2[0]) # 第一层,查看第一层容器中的具体元素内存地址id号
  18. 3120557838512
  19. >>> id(li2[-1]) # 第二层(小容器id号),查看第一层容器中的小容器list的内存地址id号
  20. 3120558904448
  21. >>> li2 # 可以看到 li2 与li1 第一层的内存地址已经发生了变化。只有第二层的内存引用地址一样
  22. ['a', 'b', [1, 2]]
  23. >>>

  尝试修改li1,查看li2的变化:

  1. >>> li1[0] = "x"
  2. >>> li1[-1][-1] = 20
  3. >>> li1
  4. ['x', 'b', [1, 20]]
  5. >>> li2 # li2 由于小容器也新生成了一个。所以即使li1小容器中的值发生改变,li2小容器中的值依然是原本的值
  6. ['a', 'b', [1, 2]]
  7. >>>

深拷贝结论:

  本体            

    1.修改不可变类型数据(如:第一层的str

    2.修改可变数据类型中的数据(如:第二层小容器list中的数据)

对应关系

  拷贝体

    1.保持原本体中的值,不发生变化

    2.保持原本体中的值,不发生变化

其他图示

b = a::赋值引用,a 和 b 都指向同一个对象。

b = a.copy():浅拷贝, a 和 b 是一个独立的对象,但他们的子对象还是指向统一对象(是引用)。

b = copy.deepcopy(a): 深度拷贝, a 和 b 完全拷贝了父对象及其子对象,两者是完全独立的。

底层剖析Python深浅拷贝的更多相关文章

  1. Python开发【第二章】:Python深浅拷贝剖析

    Python深浅拷贝剖析 Python中,对象的赋值,拷贝(深/浅拷贝)之间是有差异的,如果使用的时候不注意,就可能产生意外的结果. 下面本文就通过简单的例子介绍一下这些概念之间的差别. 一.对象赋值 ...

  2. 小学生都能学会的python(深浅拷贝)

    小学生都能学会的python(深浅拷贝) join() 把列表中的每一项用字符串拼接起来 # lst = ["汪峰", "吴君如", "李嘉欣&quo ...

  3. 【0806 | Day 9】三张图带你了解数据类型分类和Python深浅拷贝

    一.数据类型分类 二.Python深浅拷贝

  4. 关于python深浅拷贝的个人浅见

    起初,关于python的深浅拷贝,总是习惯去用传值传址的方式去考虑,发现总是get不到规律,容易记混. python有着高度自治的内存管理,而不可变对象的内存分配,则是能省则省,就是说,无论用什么拷贝 ...

  5. python深浅拷贝与赋值

    初学编程的小伙伴都会对于深浅拷贝的用法有些疑问,今天我们就结合python变量存储的特性从内存的角度来谈一谈赋值和深浅拷贝~~~ 预备知识一——python的变量及其存储 在详细的了解python中赋 ...

  6. python 深浅拷贝 进阶

    主要理解新与旧究竟在哪里 这样也就理解了 深浅拷贝 先说说赋值,事实上python中的赋值事实上是赋值了一个引用.比如: foo1=1.0 foo2=foo1 用操作符is推断时.你能够发现结果是tr ...

  7. python深浅拷贝&垃圾回收&上下文管理(with语句)

    深浅拷贝 在Python中使用copy模块用于对象的拷贝操作. 该模块提供了两个主要的方法:浅拷贝 copy.copy() 深拷贝 copy.deepcopy() 1.浅拷贝(copy) 浅拷贝: 不 ...

  8. 关于Python深浅拷贝

    拷贝: 说明:原则上就是把数据分离出来,复制其数据,并以后修改互不影响. 何来深浅拷贝的说法? 深浅拷贝的“深”和“浅”可以理解为从变量到硬盘上的物理存储介质之间的层次的多少. 下面用一个示例来解释浅 ...

  9. python 深浅拷贝 for循环删除

    ###########################总结########################### 1. 基础数据类型补充 大多数的基本数据类型的知识.已经学完了 a='aaaa' ls ...

随机推荐

  1. SpringBoot系列—简单的邮件系统

    1. 效果发送效果图 2. 邮件开发准备工作 3. springboot引入mail服务 4. 启动应用,开始4种邮件发送测试 1. 效果发送效果图 连续发送了四封邮件:普通文本邮件,带附件的邮件,内 ...

  2. OI 做题的常见错误

    会引起 Compile Error 的错误 由于这类错误过于简单,相信是个正常人都会修,故略写. int main() 写为 int mian() . 写完 struct 或 class 忘记写分号. ...

  3. Rocket - devices - TLError

    https://mp.weixin.qq.com/s/s_6qPkT2zwdqYLw5iK7_8g 简单介绍TLError的实现. 1. 继承自DevNullDevice TLError继承自DevN ...

  4. python初学者笔记(2):阿拉伯数字转换成中文大写

    题:输入一个数字,转换成中文大写的写法 可运行的程序(Python 2.7.9): # -*- coding: utf-8 -*- #在python2的py文件里面写中文,必须要添加一行声明文件编码的 ...

  5. Java实现 LeetCode 733 图像渲染(DFS)

    733. 图像渲染 有一幅以二维整数数组表示的图画,每一个整数表示该图画的像素值大小,数值在 0 到 65535 之间. 给你一个坐标 (sr, sc) 表示图像渲染开始的像素值(行 ,列)和一个新的 ...

  6. (Java实现) 删数问题

    删数问题(需知道的数学定理) 给定n位正整数a,去掉其中任意k≤n 个数字后,剩下的数字按原次序排列组成一个新 的正整数.对于给定的n位正整数a和正整数 k,设计一个算法找出剩下数字组成的新数最 小的 ...

  7. Java实现 蓝桥杯VIP 算法训练 FBI树

    问题描述 我们可以把由"0"和"1"组成的字符串分为三类:全"0"串称为B串,全"1"串称为I串,既含"0&q ...

  8. Java实现 LeetCode 56 合并区间

    56. 合并区间 给出一个区间的集合,请合并所有重叠的区间. 示例 1: 输入: [[1,3],[2,6],[8,10],[15,18]] 输出: [[1,6],[8,10],[15,18]] 解释: ...

  9. Java实现字符串的包含

    1 问题描述 给定一长字符串A和一短字符串B.请问,如何最快地判断出短字符串B中的所有字符是否都在长字符串A中?请编写一个判断函数实现此功能. 为简单起见,假设输入的字符串只包含小写英文字母.下面举几 ...

  10. java实现放麦子问题

    /* 你一定听说过这个故事.国王对发明国际象棋的大臣很佩服, 问他要什么报酬,大臣说:请在第 1 个棋盘格放 1 粒麦子, 在第 2 个棋盘格放 2 粒麦子,在第 3 个棋盘格放 4 粒麦子, 在第 ...