[Python3 填坑] 009 深拷贝与浅拷贝
1. print( 坑的信息 )
- 挖坑时间:2019/01/10
- 明细
| 坑的编码 | 内容 |
|---|---|
| Py006-3 | Python3 中的深拷贝与浅拷贝 |
2. 开始填坑
2.1 Python3.7 官方文档
2.2 赋值、切片与 copy()
# 例 1
lst1_1 = [0, 1, 2, 3, 4]
lst1_2 = lst1_1 # Python 的赋值语句不复制对象,而是在目标和对象之间建立联系
lst1_3 = lst1_1[:] # 切片
lst1_4 = lst1_1.copy() # copy()
print("lst1_1 =", lst1_1)
print("lst1_2 =", lst1_2)
print("lst1_3 =", lst1_3)
print("lst1_4 =", lst1_4)
print('-'*30)
print("id(lst1_1) =", id(lst1_1))
print("id(lst1_2) =", id(lst1_2))
print("id(lst1_3) =", id(lst1_3))
print("id(lst1_4) =", id(lst1_4))
>>>
lst1_1 = [0, 1, 2, 3, 4]
lst1_2 = [0, 1, 2, 3, 4]
lst1_3 = [0, 1, 2, 3, 4]
lst1_4 = [0, 1, 2, 3, 4]
------------------------------
id(lst1_1) = 2523757320136
id(lst1_2) = 2523757320136
id(lst1_3) = 2523757319624
id(lst1_4) = 2523757319816
分析
- lst1_1 与 lst1_2 指向同一片内存地址,是同一事物的两个名字
- 切片与 copy() 开辟了新的空间,产生的是新事物
# 例 2
lst2_1 = [111, 222, 333, 444]
lst2_2 = lst2_1
lst2_3 = lst2_1[:]
lst2_4 = lst2_1.copy()
lst2_1[0] = 'a'
print("lst2_1 =", lst2_1)
print("lst2_2 =", lst2_2)
print("lst2_3 =", lst2_3)
print("lst2_4 =", lst2_4)
print('-'*30)
lst2_2[1] = 'b'
print("lst2_1 =", lst2_1)
print("lst2_2 =", lst2_2)
print("lst2_3 =", lst2_3)
print("lst2_4 =", lst2_4)
print('-'*30)
lst2_3[2] = 'c'
print("lst2_1 =", lst2_1)
print("lst2_2 =", lst2_2)
print("lst2_3 =", lst2_3)
print("lst2_4 =", lst2_4)
print('-'*30)
lst2_4[3] = 'd'
print("lst2_1 =", lst2_1)
print("lst2_2 =", lst2_2)
print("lst2_3 =", lst2_3)
print("lst2_4 =", lst2_4)
>>>
lst2_1 = ['a', 222, 333, 444]
lst2_2 = ['a', 222, 333, 444]
lst2_3 = [111, 222, 333, 444]
lst2_4 = [111, 222, 333, 444]
------------------------------
lst2_1 = ['a', 'b', 333, 444]
lst2_2 = ['a', 'b', 333, 444]
lst2_3 = [111, 222, 333, 444]
lst2_4 = [111, 222, 333, 444]
------------------------------
lst2_1 = ['a', 'b', 333, 444]
lst2_2 = ['a', 'b', 333, 444]
lst2_3 = [111, 222, 'c', 444]
lst2_4 = [111, 222, 333, 444]
------------------------------
lst2_1 = ['a', 'b', 333, 444]
lst2_2 = ['a', 'b', 333, 444]
lst2_3 = [111, 222, 'c', 444]
lst2_4 = [111, 222, 333, 'd']
分析
- 结合例 1,可以看出,对整个列表(一个完整对象)而言
- 指向同一片地址的事物是“有难同当”的
- 指向不同地址的事物是“井水不犯河水”的
# 例 3
lst3_1 = [0, 1, 2, [3, 4, 5]]
lst3_2 = lst3_1
lst3_3 = lst3_1[:]
lst3_4 = lst3_1.copy()
print("id(lst3_1[0]) =", id(lst3_1[0]))
print("id(lst3_2[0]) =", id(lst3_2[0]))
print("id(lst3_3[0]) =", id(lst3_3[0]))
print("id(lst3_4[0]) =", id(lst3_4[0]))
print('-'*30)
print("id(lst3_1[3]) =", id(lst3_1[3]))
print("id(lst3_2[3]) =", id(lst3_2[3]))
print("id(lst3_3[3]) =", id(lst3_3[3]))
print("id(lst3_4[3]) =", id(lst3_4[3]))
print('-'*30)
print("id(lst3_1[3][0]) =", id(lst3_1[3][0]))
print("id(lst3_2[3][0]) =", id(lst3_2[3][0]))
print("id(lst3_3[3][0]) =", id(lst3_3[3][0]))
print("id(lst3_4[3][0]) =", id(lst3_4[3][0]))
>>>
id(lst3_1[0]) = 140733084593888
id(lst3_2[0]) = 140733084593888
id(lst3_3[0]) = 140733084593888
id(lst3_4[0]) = 140733084593888
------------------------------
id(lst3_1[3]) = 2523758754824
id(lst3_2[3]) = 2523758754824
id(lst3_3[3]) = 2523758754824
id(lst3_4[3]) = 2523758754824
------------------------------
id(lst3_1[3][0]) = 140733084593984
id(lst3_2[3][0]) = 140733084593984
id(lst3_3[3][0]) = 140733084593984
id(lst3_4[3][0]) = 140733084593984
分析
- 这些列表内部,无论“第一层”还是“第二层”,对应元素的地址其实是相同的
# 例 4
lst4_1 = [0, 1, 2, [30, 31, 32]]
lst4_2 = lst4_1
lst4_3 = lst4_1[:]
lst4_4 = lst4_1.copy()
lst4_1[3].append(33)
print("lst4_1 =", lst4_1)
print("lst4_2 =", lst4_2)
print("lst4_3 =", lst4_3)
print("lst4_4 =", lst4_4)
print('-'*40)
lst4_3[3][0] = 66
print("lst4_1 =", lst4_1)
print("lst4_2 =", lst4_2)
print("lst4_3 =", lst4_3)
print("lst4_4 =", lst4_4)
print('-'*40)
lst4_4[3][1] = 888
print("lst4_1 =", lst4_1)
print("lst4_2 =", lst4_2)
print("lst4_3 =", lst4_3)
print("lst4_4 =", lst4_4)
>>>
lst4_1 = [0, 1, 2, [30, 31, 32, 33]]
lst4_2 = [0, 1, 2, [30, 31, 32, 33]]
lst4_3 = [0, 1, 2, [30, 31, 32, 33]]
lst4_4 = [0, 1, 2, [30, 31, 32, 33]]
----------------------------------------
lst4_1 = [0, 1, 2, [66, 31, 32, 33]]
lst4_2 = [0, 1, 2, [66, 31, 32, 33]]
lst4_3 = [0, 1, 2, [66, 31, 32, 33]]
lst4_4 = [0, 1, 2, [66, 31, 32, 33]]
----------------------------------------
lst4_1 = [0, 1, 2, [66, 888, 32, 33]]
lst4_2 = [0, 1, 2, [66, 888, 32, 33]]
lst4_3 = [0, 1, 2, [66, 888, 32, 33]]
lst4_4 = [0, 1, 2, [66, 888, 32, 33]]
分析
- 像例 4 这样列表中嵌套的列表(第二层),赋值、切片、copy() 都是“有难同当”的
2.3 copy 模块
# 例 5
import copy # 导入 copy 模块
lst5_1 = [0, 1, 2, [30, 31]]
lst5_2 = copy.copy(lst5_1) # 浅拷贝
lst5_3 = copy.deepcopy(lst5_1) # 深拷贝
print("lst5_1 =", lst5_1)
print("lst5_2 =", lst5_2)
print("lst5_3 =", lst5_3)
print('-'*40)
print("id(lst5_1) =", id(lst5_1))
print("id(lst5_2) =", id(lst5_2))
print("id(lst5_3) =", id(lst5_3))
print('-'*40)
lst5_1.append(4)
print("lst5_1 =", lst5_1)
print("lst5_2 =", lst5_2)
print("lst5_3 =", lst5_3)
print('-'*40)
lst5_1[3].append(32)
print("lst5_1 =", lst5_1)
print("lst5_2 =", lst5_2)
print("lst5_3 =", lst5_3)
>>>
lst5_1 = [0, 1, 2, [30, 31]]
lst5_2 = [0, 1, 2, [30, 31]]
lst5_3 = [0, 1, 2, [30, 31]]
----------------------------------------
id(lst5_1) = 2523758966408
id(lst5_2) = 2523758966280
id(lst5_3) = 2523758881096
----------------------------------------
lst5_1 = [0, 1, 2, [30, 31], 4]
lst5_2 = [0, 1, 2, [30, 31]]
lst5_3 = [0, 1, 2, [30, 31]]
----------------------------------------
lst5_1 = [0, 1, 2, [30, 31, 32], 4]
lst5_2 = [0, 1, 2, [30, 31, 32]]
lst5_3 = [0, 1, 2, [30, 31]]
分析
- 深、浅拷贝均与赋值不同
- 切片、copy() 可以看作浅拷贝
- 浅拷贝顶得住“第一层”却顶不住“第二层”
- 深拷贝的“第二层”也“不容侵犯”
# 例 6
import copy # 导入 copy 模块
lst6_1 = {'a':"apple", 'b':["banana"], 'c':["carambola", "cherry", "coconut"]}
lst6_2 = copy.copy(lst6_1) # 浅拷贝
lst6_3 = copy.deepcopy(lst6_1) # 深拷贝
print("id(lst6_1) =", id(lst6_1))
print("id(lst6_2) =", id(lst6_2))
print("id(lst6_3) =", id(lst6_3))
print('-'*40)
print("id(lst6_1['a']) =", id(lst6_1['a']))
print("id(lst6_2['a']) =", id(lst6_2['a']))
print("id(lst6_3['a']) =", id(lst6_3['a']))
print('-'*40)
print("id(lst6_1['b']) =", id(lst6_1['b']))
print("id(lst6_2['b']) =", id(lst6_2['b']))
print("id(lst6_3['b']) =", id(lst6_3['b']))
print('-'*40)
print("id(lst6_1['c']) =", id(lst6_1['c']))
print("id(lst6_2['c']) =", id(lst6_2['c']))
print("id(lst6_3['c']) =", id(lst6_3['c']))
print('-'*40)
lst6_1['a'] = "arbutus"
print("lst6_1['a'] =", lst6_1['a'])
print("lst6_2['a'] =", lst6_2['a'])
print("lst6_3['a'] =", lst6_3['a'])
print('-'*40)
lst6_1['b'].append("berry")
print("lst6_1['b'] =", lst6_1['b'])
print("lst6_2['b'] =", lst6_2['b'])
print("lst6_3['b'] =", lst6_3['b'])
print('-'*40)
lst6_1['c'].remove("cherry")
print("lst6_1['c'] =", lst6_1['c'])
print("lst6_2['c'] =", lst6_2['c'])
print("lst6_3['c'] =", lst6_3['c'])
>>>
id(lst6_1) = 2298694416712
id(lst6_2) = 2298694594848
id(lst6_3) = 2298694594920
----------------------------------------
id(lst6_1['a']) = 2298693712952
id(lst6_2['a']) = 2298693712952
id(lst6_3['a']) = 2298693712952
----------------------------------------
id(lst6_1['b']) = 2298694533576
id(lst6_2['b']) = 2298694533576
id(lst6_3['b']) = 2298694533768
----------------------------------------
id(lst6_1['c']) = 2298694533704
id(lst6_2['c']) = 2298694533704
id(lst6_3['c']) = 2298694533640
----------------------------------------
lst6_1['a'] = arbutus
lst6_2['a'] = apple
lst6_3['a'] = apple
----------------------------------------
lst6_1['b'] = ['banana', 'berry']
lst6_2['b'] = ['banana', 'berry']
lst6_3['b'] = ['banana']
----------------------------------------
lst6_1['c'] = ['carambola', 'coconut']
lst6_2['c'] = ['carambola', 'coconut']
lst6_3['c'] = ['carambola', 'cherry', 'coconut']
分析
- 字典与列表稍有不同
- 若字典的值是列表,则该列表属于“第二层”
2.4 小结
深拷贝,拷贝的是原对象内部的元素,是一个真正的副本
浅拷贝,拷贝的是原对象内部数据的地址,并不是一个真正的副本
- 拷贝后的新对象占用新的空间,但其内部的元素指向原对象内部对应元素的地址
- 有“顶层拷贝”之称,即不变动拷贝后新对象的第一层元素
- 当原对象中非第一层的可变元素发生变化时,新对象中的对应元素同步变化
2.5 copy 模块的补充
2.5.1 使用场合
- copy 模块常用于复合对象
- 复合对象:包含其他对象的对象,如列表、类实例等
- 它不能拷贝模块、方法、堆栈跟踪、堆栈帧、文件、套接字、窗口、数组等
- 必要时,可以重写 copy.copy(x) 和 copy.deepcopy(x[, memo])
2.5.2 深拷贝的问题与解决
问题
- 递归对象(直接或间接包含对自身引用的复合对象)可能导致递归循环
- 因为深拷贝会复制原对象的一切,所以可能复制过多的内容;例如,打算在副本之间共享的数据
解决方法
- 保存在当前复制过程中已经复制的对象的 memo 字典
- 让用户定义的类重写复制操作或复制的组件集
2.5.3 浅拷贝的作用
- 提前做浅拷贝可以防止后期因变量名众多而产生混乱
- 可应用于“联合账号”等
倘若阁下发现在下错误之处,还请不吝赐教!谢谢!
[Python3 填坑] 009 深拷贝与浅拷贝的更多相关文章
- [Python3 填坑] 006 “杠零”,空字符的使用
目录 1. print( 坑的信息 ) 2. 开始填坑 2.1 \0 是空字符,输出时看不到它,但它占 1 个字符的长度 2.2 \0 "遇八进制失效" 2.3 \0 与 '' 不 ...
- [Python3 填坑] 004 关于八进制
目录 1. print( 坑的信息 ) 2. 开始填坑 2.1 问题的由来 2.2 问题的解决 2.2.1 先说结论 2.2.2 八进制的用途 2.2.3 少废话,上例子 1. print( 坑的信息 ...
- [Python3 填坑] 001 格式化符号 & 格式化操作符的辅助指令
目录 1. print( 坑的信息 ) 2. 开始填坑 2.1 Python 格式化符号表 举例说明 (1) %c (2) %s 与 %d (3) %o (4) %x (5) %f (6) %e (7 ...
- [Python3 填坑] 012 字典的遍历在 Python2 与 Python3 中区别
目录 1. print( 坑的信息 ) 2. 开始填坑 2.1 Python2 中字典的遍历 2.2 Python3 中字典的遍历 2.3 结论 1. print( 坑的信息 ) 挖坑时间:2019/ ...
- [Python3 填坑] 005 如何“响铃”
目录 1. print( 坑的信息 ) 2. 开始填坑 2.1 问题的由来 2.2 问题的解决 1. print( 坑的信息 ) 挖坑时间:2019/01/08 明细 坑的编码 内容 Py004-2 ...
- [Python3 填坑] 003 关键字?保留字?预留字?
目录 1. print( 坑的信息 ) 2. 开始填坑 2.1 问题的由来 2.2 网上搜索 2.3 结论 2.4 后记 1. print( 坑的信息 ) 挖坑时间:2019/01/04 明细 坑的编 ...
- [Python3 填坑] 018 组装类的几个例子
目录 1. print( 坑的信息 ) 2. 开始填坑 2.1 MetaClass 举例 2.2 type 举例 2.3 MetaClass 举例 1. print( 坑的信息 ) 挖坑时间:2019 ...
- [Python3 填坑] 017 实例方法、静态方法、类方法的区别
目录 1. print( 坑的信息 ) 2. 开始填坑 2.1 先上例子 2.2 分析 1. print( 坑的信息 ) 挖坑时间:2019/04/07 明细 坑的编码 内容 Py024-1 实例方法 ...
- [Python3 填坑] 016 对 __getattr__ 和 __setattr__ 举例
目录 1. print( 坑的信息 ) 2. 开始填坑 2.1 __getattr__ 2.2 __setattr__ 1. print( 坑的信息 ) 挖坑时间:2019/04/07 明细 坑的编码 ...
随机推荐
- 牛客假日团队赛5 F 随机数 BZOJ 1662: [Usaco2006 Nov]Round Numbers 圆环数 (dfs记忆化搜索的数位DP)
链接:https://ac.nowcoder.com/acm/contest/984/F 来源:牛客网 随机数 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语言6 ...
- Decision Trees 决策树
Decision Trees (DT)是用于分类和回归的非参数监督学习方法. 目标是创建一个模型,通过学习从数据特征推断出的简单决策规则来预测目标变量的值. 例如,在下面的例子中,决策树从数据中学习用 ...
- python 导入模块、包
1. 模块:一个有逻辑的python文件,包含变量.函数.类等.2. 包:一个包含__init__.py的文件夹,存放多个模块 import 本质是路径搜索,查找sys.path下有无你导入的 pac ...
- webpack 零基础到工程实战(1)
webpack resolve:resolve 配置是帮助 webpack 查找依赖模块resolve.alias 是最常用的配置,通过设置 alias 可以帮助 webpack 更快查找模块依赖,而 ...
- 解决使用脚手架构建项目缺失node_modules文件夹文件问题
昨晚,在教我前端交流群里面的朋友搭建vue开发环境和构建vue项目的时候发现我自己之前能正常构建vue项目的现在却不行了,排查之下发现 通过脚手架构建项目的时候项目缺失了node_modules文件夹 ...
- springboot + 注解 + 拦截器 + JWT 实现角色权限控制
1.关于JWT,参考: (1)10分钟了解JSON Web令牌(JWT) (2)认识JWT (3)基于jwt的token验证 2.JWT的JAVA实现 Java中对JWT的支持可以考虑使用JJWT开源 ...
- BZOJ 3357: [Usaco2004]等差数列 动态规划
Code: #include<bits/stdc++.h> #define setIO(s) freopen(s".in","r",stdin) # ...
- POJ 3111 K Best ( 二分 )
题意 : 给出 N 个物品的价值和重量,然后要求选出 K 个物品使得选出来物品的单位重量价值最大,最后输出被选物品的编号. 分析 : 很容易去想先算出每个物品的单位价值然后升序排序取前 K 个,但是 ...
- MySQL Password Expired
好久没有登录MySQL,登录的时候遇到如下提示: 尝试使用命令行登录,发现是可以使用之前的密码登录的,如下: 只是登录之后,发现做不了什么操作.并且使用,alter 语句重设密码也没有成功,如下: 试 ...
- Initialization of bean failed; nested exception is java.lang.
网上搜寻各种解说,applicationContext-hibernate.xml 配置错误,jar冲突等等 现场错误图: 解决方法: asm-attrs.jar cglib-nodep-2.1_3. ...