Python 列表切片陷阱:引用、复制与深复制
Python 列表的切片和赋值操作很基础,之前也遇到过一些坑,以为自己很懂了。但今天刷 Codewars 时发现了一个更大的坑,故在此记录。
Python 列表赋值:复制“值”还是“引用”?
很多入门 Python 的人会犯这样一个错误:在赋值操作=中搞不清是赋了“值”还是“引用”。比如:
a = [1, 2, 3]
b = a
b[0] = 10 # 更改列表 b 的第一个元素,但 a 现在也被更改为了 [10, 2, 3]
他可能只想改变列表b,但实际上这样也会改变列表a。
因为b实际上是列表a的另一个引用,a和b是同一个对象,id(a) == id(b),所以更改b也会更改a。这个应该大部分人都知道。所以正确的代码应该使用切片来进行列表的复制:
a = [1, 2, 3]
b = a[:] # 使用切片进行列表复制
b[0] = 10 # 此时 a 和 b 是两个不同的对象
二维列表引发的思考:列表的本质
好的,现在我们确定切片能够进行列表的复制。那我们就能心安理得地改动新的列表了吗?请看二维列表(二维数组):
a = [[1, 2, 3], [4, 5, 6]]
b = a[:]
b[0][0] = 10
此时,a还是被改动了!
原因是,虽然id(a) == id(b)为False,a和b确实不是同一个对象。但它们的元素都是同一个对象——id(a[0]) == id(b[0]),id(a[1]) == id(b[1])。因为列表里存储的是对象的引用!
列表 list 终究只是个容器。就像 tuple 本身是 immutable (不可变)的,但它只是容器,它可以存储一个可变对象,因此呈现出一种可以被改动的“假象”。例如:
>>> a = ([1],)
>>> a[0][0] = 2
>>> a
([2],)
所以容器和它存储的对象不能混为一谈。所以对于这种二维列表,想要进行完全的复制,请直接使用copy.deepcopy()深度复制。
如果只想复制一部分(切片),那可以先复制再切片:
>>> import copy
>>> a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> b = copy.deepcopy(a)[1:]
>>> b[0][0] = 100
>>> a
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> b
[[100, 5, 6], [7, 8, 9]]
此时修改b没有影响到a。
Python 列表切片陷阱:引用、复制与深复制的更多相关文章
- Python赋值、浅复制和深复制
Python赋值.浅复制和深复制 首先我们需要知道赋值和浅复制的区别: 赋值和浅复制的区别 赋值,当一个对象赋值给另一个新的变量时,赋的其实是该对象在栈中的地址,该地址指向堆中的数据.即赋值后,两 ...
- Python中的浅复制、深复制
参考 https://docs.python.org/3/library/copy.html?highlight=copy%20copy#copy.copy https://en.wikipedia. ...
- Java中引用的浅复制和深复制
Java中除了基本类型int,char,double等的赋值是按照值传递之外,其余的类型和对象都是按照引用进行传递的. 下面来看一个关于引用的例子. package referenceCopy;// ...
- Python笔记21-------浅复制和深复制、赋值
上面图表示浅复制和深复制,针对顶层对象来说,赋值为引用,浅复制和深复制都是复制一个新的对象. 针对子对象来说,浅复制为引用.深复制就是复制两个一样的. 1.赋值 A= [ 1,2,3, [ 'a',' ...
- 也来谈一谈js的浅复制和深复制
1.浅复制VS深复制 本文中的复制也可以称为拷贝,在本文中认为复制和拷贝是相同的意思.另外,本文只讨论js中复杂数据类型的复制问题(Object,Array等),不讨论基本数据类型(null,unde ...
- js的浅复制和深复制
1.浅复制VS深复制 本文中的复制也可以称为拷贝,在本文中认为复制和拷贝是相同的意思.另外,本文只讨论js中复杂数据类型的复制问题(Object,Array等),不讨论基本数据类型(null,unde ...
- iOS 浅复制和深复制的深层理解,含示例
转载:https://www.zybuluo.com/MicroCai/note/50592 版权归 @MicroCai 所有 以下是正文: 浅复制就是指针拷贝:深复制就是内容拷贝. 集合的浅复制 ( ...
- java基础-浅复制与深复制的理解
浅复制与深复制在很多编程语言中都有出现,那么什么是浅复制,什么是深复制呢? 要区分浅复制与深复制,首先我们要明确什么是复制,怎样才算是复制.复制的例子在生活中也随处可见,如复印一份文档,复制一段文字等 ...
- 深度解析javascript中的浅复制和深复制
原文:深度解析javascript中的浅复制和深复制 在谈javascript的浅复制和深复制之前,我们有必要在来讨论下js的数据类型.我们都知道有Number,Boolean,String,Null ...
随机推荐
- Python 下划线
单下划线 "单下划线" 开始的成员变量叫做保护变量,意思是只有类对象和自类对象自己能访问到这些变量. 例子:以单下划线开头(_foo)的代表不能直接访问的类属性,需通过类提供的接口 ...
- app开发中的经常遇到的问题
1.banner不显示: 原因:配置文件中的 域名写错了. img_path = https://www.beicaiduo.com/znbsite/static/tinymce/upload/ 解决 ...
- Go package(1) time 用法
golang使用的版本: go version go1.10.3 一:功能介绍 time的一些功能,比如时区,像linux中的定时器,时间计算等 格式化时间 时区(Location) 时间计算 Tic ...
- java基础-容器-Set
Set:set不存重复元素,如果是使用set存储java预定义的Integer,String等类型会很简单,如果是存储自定义类型的数据类型,就必须要重新定义equals()方法以确保set中保存的对象 ...
- java eclipse中使用wsdl生成soap 的客户端代码
项目右键--> new --> other finish完成
- jar包中File 文件找不到的异常分析与解决
源链接: http://hxraid.iteye.com/blog/483115#comments 我们常常在代码中读取一些资源文件(比如图片,音乐,文本等等).在单独运行的时候这些简单的处理当然不会 ...
- python之map,filter
map和filter是python里面比较重要的BIF,map的主要作用就是对集合里面的每一个元素进行处理,filter的作用就是过滤集合,具体功能如下 t =lambda x:x%2 list(fi ...
- python中opencv的安装
1.得到opencv的安装包: 2.把安装包中的cv.py, cv2.pd放到一个文件夹中,并把这个文件夹放到D:\Anaconda2\Lib\site-packages中: 3.添加新的变量,变量名 ...
- 激光推送(ios,安卓)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.I ...
- Linux CentOS7 安装wkhtmltopdf工具
wkhtmltopdf是一款将html文件转换成pdf格式的优秀的文件内容转换工具.它使用QT作为渲染引擎,目前它的RELEASE版尚不支持flex布局的Html5代码转换.使用flex的嵌套元素将会 ...