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 ...
随机推荐
- 使用Docker安装Nginx
启动命令 docker run -d -p : --name nginx -v $PWD/nginx.conf:/etc/nginx/nginx.conf -v $PWD/conf.d/:/etc/n ...
- ArcGis Python脚本——遍历输出面或折线要素的折点坐标
有示例要素类如下 经过下面代码处理 #遍历输出面或折线要素的折点坐标 #infc:输入要素类 # code source: https://www.cnblogs.com/yzhyingcool/# ...
- numpy&pandas补充常用示例
Numpy [数组切片] In [115]: a = np.arange(12).reshape((3,4)) In [116]: a Out[116]: array([[ 0, 1, 2, 3], ...
- Kindle复活记
此前,2015年为了配合拆机堂的内容项目,我们将全新Kindle PaperWhite 3进行全球首拆,让网友们第一时间全面了解了Kindle PaperWhite 3的内部构造.但由于进行深度拆解, ...
- C# - 设计模式 - 钩子模式
钩子模式 问题场景 如何控制抽象类的行为?解决办法是靠钩子!抽象类公布一个虚方法,由子类自行决定是否重写它,抽象类以钩子做判定,如果返回真则执行某个方法,否则不执行.为什么钩子不能是抽象的,因为如果钩 ...
- dubbo注册中心
官方推荐的是zookeeper注册中心. 1.Multicast 注册中心 Multicast 注册中心不需要启动任何中心节点,只要广播地址一样,就可以互相发现. 提供方启动时广播自己的地址消费方启动 ...
- Pytorch学习笔记(二)---- 神经网络搭建
记录如何用Pytorch搭建LeNet-5,大体步骤包括:网络的搭建->前向传播->定义Loss和Optimizer->训练 # -*- coding: utf-8 -*- # Al ...
- 3D Slicer中文教程(七)—图像中值滤波
1.中值滤波概念 中值滤波是对一个滑动窗口内的诸像素灰度值排序,用其中值代替窗口中心象素的原来灰度值,它是一种非线性的图像平滑法,它对脉冲干扰级椒盐噪声的抑制效果好,在抑制随机噪声的同时能有效保护边缘 ...
- input子系统 KeyPad-Touch上报数据格式与机制【转】
转自:https://www.cnblogs.com/0822vaj/p/4185634.html -------------------------------------------------- ...
- kibana转码显示
$('.truncate-by-height').each((i, dom) => { $(dom).html(decodeURIComponent($(dom).html())) })