今天在写一个小程序的时候用到了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的更多相关文章

  1. Numpy copy & deep copy

    1. '='的赋值方式会带有关联性 >>> import numpy as np >>> a = np.arange(4) >>> b = a & ...

  2. 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的第一 ...

  3. shallow copy & deep copy

    1.深复制与浅复制的概念 ->浅复制(shallow copy)概念   在SDK Guides中(搜索copy),官方给出的浅复制概念为: Copying compound objects, ...

  4. Shallow copy and Deep copy

    Shallow copy and Deep copy 第一部分: 一.来自wikipidia的解释: Shallow copy One method of copying an object is t ...

  5. python deep copy and shallow copy

    Python中对于对象的赋值都是引用,而不是拷贝对象(Assignment statements in Python do not copy objects, they create bindings ...

  6. python中的shallow copy 与 deep copy

    今天在写代码的时候遇到一个奇葩的问题,问题描述如下: 代码中声明了一个list,将list作为参数传入了function1()中,在function1()中对list进行了del()即删除了一个元素. ...

  7. 由Python的浅拷贝(shallow copy)和深拷贝(deep copy)引发的思考

    首先查看拷贝模块(copy)发现: >>> help(copy)Help on module copy:NAME    copy - Generic (shallow and dee ...

  8. shallow copy 和 deep copy 的示例

    本文属原创,转载请注明出处:http://www.cnblogs.com/robinjava77/p/5481874.html   (Robin) Student package base; impo ...

  9. JavaScript 深拷贝(deep copy)和浅拷贝(shallow copy)

    参考: [进阶4-1期]详细解析赋值.浅拷贝和深拷贝的区别 How to differentiate between deep and shallow copies in JavaScript 在编程 ...

随机推荐

  1. Atitit.收银系统模块架构attilax 总结

    Atitit.收银系统模块架构attilax 总结 1. 常规收银系统模块结构1 1.1. 商品管理1 1.2. 会员系统1 1.3. 报表系统1 1.4. 会员卡系统1 1.5. 库存管理1 2.  ...

  2. FPGA开发要懂得使用硬件分析仪调试——ILA

    0. ILA概述在FPGA开发中,当我们写完代码,进行仿真,确定设计没有问题后,下载到硬件上一般都能按照我们的设计意愿执行相应功能.但这也并非绝对的,有时候你会遇到一些突然情况,比如时序问题或者仿真时 ...

  3. Redis命令学习-string类型操作

    APPEND key value     假设key已经存在,而且为字符串.那么这个命令会把value追加到原来值的末尾.假设key不存在.首先创建一个空字符串,再运行追加操作.     返回值:返回 ...

  4. 小程序swiper配置参数使用

    不管什么项目,一个轮播是基本少不了的,现在就来踩下微信小程序的swiper吧! 首先打开文档,可以看到下面这些参数:(https://mp.weixin.qq.com/debug/wxadoc/dev ...

  5. spring reactor记录操作日志

    1.注册日志的类: @Configuration@EnableReactorpublic class ReactorConfig { /** * * 〈注册审计日志 Reactor〉 */ @Bean ...

  6. Unity3d中使用自带动画系统制作下雨效果(二)

    接着昨天的(一),今天上下雨效果的后半部分.在最后附上网盘链接,有使用的素材及本次的工程源文件,想看看的童鞋可以下载~~ 下雨效果分两部分:地上的涟漪和空中的雨滴.那么现在就开始,是使用unity3d ...

  7. 非侵入式Ajax

    基本准备 首先,新建一个ASP.NET MVC 3的空项目. 然后新增一个Model,代码如下: using System; using System.Collections.Generic; usi ...

  8. 应用市场出新规,国内千款应用TargetSdkVersion调查分析

    ​​​近期,谷歌针对Google Play上架应用发布强制性适配Android 8.0公告,要求自2018 年 8 月 1 日起,所有向 Google Play 首次提交的新应用都必须基于 Andro ...

  9. 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 ...

  10. [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 ...