Shallow Copy & Deep Copy in Python list
今天在写一个小程序的时候用到了2维数组, 顺手就写成了[[0.0]*length]*length, 结果为了这个小错,调试了半个多小时,
其实之前对与浅复制和深复制已经做过学习和总结, 但真正编程用到这些知识时还是掉入了陷阱中. 所以在此做进一步的总结:
本文通过几个实例来说明Python中list的深复制和浅复制:
>>> a = [[]] * 10
>>> a
[[], [], [], [], [], [], [], [], [], []]
>>> a[0][0] = 10 #NO WAY
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list assignment index out of range
>>> a[0].append(1)
>>> a
[[1], [1], [1], [1], [1], [1], [1], [1], [1], [1]]
a[0].append(1)后, 如果a的输出结果让你感到有些困惑,你可以参考这里(原因是Python中的*运算采用的是浅复制).
同样的道理,下面的代码我们应该都能够理解:
>>> a[3].append(9)
>>> a
[[1, 9], [1, 9], [1, 9], [1, 9], [1, 9], [1, 9], [1, 9], [1, 9], [1, 9], [1, 9]]
>>> a[2][1] = 3
>>> a
[[1, 3], [1, 3], [1, 3], [1, 3], [1, 3], [1, 3], [1, 3], [1, 3], [1, 3], [1, 3]]
让我们一起来分析一下:
对于a(理解为一个2维数组)中的每一个元素都是一个list(理解为一个1维数组), 但我们需要注意的是a的每一个元素
a[0],a[1],a[2]...指向的是同一段内存区域(浅复制),所以更改(修改值或添加值)任何一个元素(a[0]或a[1]...a[9])都会直接影
响到其它的元素.
如何验证a中的每一个元素a[0], a[1],...,a[9]指向同一段内存区域? 可以通过id方法来验证:
>>> id.__doc__
"id(object) -> integer Return the identity of an object. This is guaranteed to be unique among
simultaneously existing objects. (Hint: it's the object's memory address.)"
>>> a = [[]]*10
>>> a
[[], [], [], [], [], [], [], [], [], []]
>>> id(a[0])
3071938316L
>>> id(a[1])
3071938316L
>>> a[0].append(1)
>>> a
[[1], [1], [1], [1], [1], [1], [1], [1], [1], [1]]
>>> id(a[0])
3071938316L
>>> id(a[1])
3071938316L
>>>
注意:虽然a的每一个元素a[0],a[1],a[2]...指向的是同一段内存区域,但a中的各个元素是独立的元素(他们相同但不同一),
也就是说删除掉任何一个数据对其他的数据没有任何影响:
>>> a = [[]] * 10
>>> a
[[], [], [], [], [], [], [], [], [], []]
>>> a[0].append(1)
>>> a
[[1], [1], [1], [1], [1], [1], [1], [1], [1], [1]]
>>> len(a)
10
>>> del(a[2])
>>> a
[[1], [1], [1], [1], [1], [1], [1], [1], [1]]
>>> len(a)
9
那么应该怎么实现深复制呢?其实在前面提到的文章中已经介绍了这一方法:
>>> c = [[] for i in range(10)]
>>> c
[[], [], [], [], [], [], [], [], [], []]
>>> c[0].append(3)
>>> c
[[3], [], [], [], [], [], [], [], [], []]
>>>
至此, 我觉得还有一点需要说明:
一定要理解*操作的对象是谁, 例如: [2]*10得到[2, 2, 2, 2, 2, 2, 2, 2, 2, 2], *10操作的对象是[]中的2, 也就是说*10操
作使list中的元素2复制10次. 同理[[]]*10得到[[], [], [], [], [], [], [], [], [], []],*10操作的对象是[]中的[], 也就是说*10
操作使list中的元素[]浅复制10次, 这10个空list指向内存中相同的区域(参见上面用id验证部分).
下面用2段代码作为对比列出来, 便于查看:
>>> a = [2] * 10
>>> a
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
>>> id(a[0])
164067492
>>> id(a[1])
164067492
>>> a[0] = 1 #NOTE
>>> id(a[0]) #NOTE
164067504
>>> id(a[1])
164067492
>>>
>>> b = [[]] * 10
>>> b
[[], [], [], [], [], [], [], [], [], []]
>>> id(b[0])
3072965964L
>>> id(b[1])
3072965964L
>>> b[0].append(10)
>>> id(b[0])
3072965964L
>>> id(b[1])
3072965964L
>>> b
[[10], [10], [10], [10], [10], [10], [10], [10], [10], [10]]
>>> b[0][0] = 1
>>> b
[[1], [1], [1], [1], [1], [1], [1], [1], [1], [1]]
>>> id(b[0])
3072965964L
>>> id(b[1])
3072965964L
>>> b[0] = [10]
>>> b
[[10], [1], [1], [1], [1], [1], [1], [1], [1], [1]]
>>> id(b[1])
3072965964L
>>> id(b[0])
3072965996L
>>>
Shallow Copy & Deep Copy in Python list的更多相关文章
- Numpy copy & deep copy
1. '='的赋值方式会带有关联性 >>> import numpy as np >>> a = np.arange(4) >>> b = a & ...
- Numpy的学习6-深浅赋值(copy&deep copy)
# = 的赋值方式会带有关联性 import numpy as np a = np.arange(4) # array([0, 1, 2, 3]) b = a c = a d = b # 改变a的第一 ...
- shallow copy & deep copy
1.深复制与浅复制的概念 ->浅复制(shallow copy)概念 在SDK Guides中(搜索copy),官方给出的浅复制概念为: Copying compound objects, ...
- Shallow copy and Deep copy
Shallow copy and Deep copy 第一部分: 一.来自wikipidia的解释: Shallow copy One method of copying an object is t ...
- python deep copy and shallow copy
Python中对于对象的赋值都是引用,而不是拷贝对象(Assignment statements in Python do not copy objects, they create bindings ...
- python中的shallow copy 与 deep copy
今天在写代码的时候遇到一个奇葩的问题,问题描述如下: 代码中声明了一个list,将list作为参数传入了function1()中,在function1()中对list进行了del()即删除了一个元素. ...
- 由Python的浅拷贝(shallow copy)和深拷贝(deep copy)引发的思考
首先查看拷贝模块(copy)发现: >>> help(copy)Help on module copy:NAME copy - Generic (shallow and dee ...
- shallow copy 和 deep copy 的示例
本文属原创,转载请注明出处:http://www.cnblogs.com/robinjava77/p/5481874.html (Robin) Student package base; impo ...
- JavaScript 深拷贝(deep copy)和浅拷贝(shallow copy)
参考: [进阶4-1期]详细解析赋值.浅拷贝和深拷贝的区别 How to differentiate between deep and shallow copies in JavaScript 在编程 ...
随机推荐
- Atitit.收银系统模块架构attilax 总结
Atitit.收银系统模块架构attilax 总结 1. 常规收银系统模块结构1 1.1. 商品管理1 1.2. 会员系统1 1.3. 报表系统1 1.4. 会员卡系统1 1.5. 库存管理1 2. ...
- FPGA开发要懂得使用硬件分析仪调试——ILA
0. ILA概述在FPGA开发中,当我们写完代码,进行仿真,确定设计没有问题后,下载到硬件上一般都能按照我们的设计意愿执行相应功能.但这也并非绝对的,有时候你会遇到一些突然情况,比如时序问题或者仿真时 ...
- Redis命令学习-string类型操作
APPEND key value 假设key已经存在,而且为字符串.那么这个命令会把value追加到原来值的末尾.假设key不存在.首先创建一个空字符串,再运行追加操作. 返回值:返回 ...
- 小程序swiper配置参数使用
不管什么项目,一个轮播是基本少不了的,现在就来踩下微信小程序的swiper吧! 首先打开文档,可以看到下面这些参数:(https://mp.weixin.qq.com/debug/wxadoc/dev ...
- spring reactor记录操作日志
1.注册日志的类: @Configuration@EnableReactorpublic class ReactorConfig { /** * * 〈注册审计日志 Reactor〉 */ @Bean ...
- Unity3d中使用自带动画系统制作下雨效果(二)
接着昨天的(一),今天上下雨效果的后半部分.在最后附上网盘链接,有使用的素材及本次的工程源文件,想看看的童鞋可以下载~~ 下雨效果分两部分:地上的涟漪和空中的雨滴.那么现在就开始,是使用unity3d ...
- 非侵入式Ajax
基本准备 首先,新建一个ASP.NET MVC 3的空项目. 然后新增一个Model,代码如下: using System; using System.Collections.Generic; usi ...
- 应用市场出新规,国内千款应用TargetSdkVersion调查分析
近期,谷歌针对Google Play上架应用发布强制性适配Android 8.0公告,要求自2018 年 8 月 1 日起,所有向 Google Play 首次提交的新应用都必须基于 Andro ...
- LeetCode532. K-diff Pairs in an Array
Description Given an array of integers and an integer k, you need to find the number of unique k-dif ...
- [Tomcat]无法使用tomcat6.exe启动服务解决办法, The system cannot find the Registry key for service 'tomcat7'
重新配置环境变量后,可以使用startup.bat启动服务, 但是无法使用tomcat6.exe启动服务, 错误信息: [2011-03-10 18:51:49] [warn] The system ...