Python中append浅拷贝机制

news2025/1/11 23:59:36

关于深浅拷贝,最直观的理解就是:

  • 深拷贝:拷贝的程度深,自己新开辟了一块内存,将被拷贝内容全部拷贝过来了;

  • 浅拷贝:拷贝的程度浅,只拷贝原数据的首地址,然后通过原数据的首地址,去获取内容。

这两者的优缺点对比:

  • 深拷贝拷贝程度高,将原数据复制到新的内存空间中。改变拷贝后的内容不影响原数据内容。但是深拷贝耗时长,且占用内存空间。

  • 浅拷贝拷贝程度低,只复制原数据的地址。其实是将副本的地址指向原数据地址。修改副本内容,是通过当前地址指向原数据地址,去修改。所以修改副本内容会影响到原数据内容。但是浅拷贝耗时短,占用内存空间少。

Python内存引用

在C语言中,在声明变量的时候,int aint b,这两条语句为ab两个变量分别赋予了两块不同的内存空间,然后赋值的时候再将相应的值存储到对应的存储空间。但是在Python中变量的赋值与C语言是截然不同的,考虑下面的代码:

>>> a = 2
>>> b = 2
>>> id(a)
140736259334576
>>> id(b)
140736259334576

id函数用于获取对象的内存地址,可以发现,变量a和变量b的内存地址竟然一样!

在Python中,先生成对象,变量再对对象进行引用,在这个例子中,1就是对象,然后a再对1进行引用,由于常数是不可变类型,所以1的内存空间是一样的,所以a,b引用的是用一块内存空间。虽然变量名不一样,但是他们引用的对象是相同的。

当然上面举的例子是int类型的,这属于不可变类型。如果是list或者dict呢?来看看下面的例子:

>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> id(a)
3145735383560
>>> id(b)
3145735414984

内存地址不一致!基于此,我们步入今天的主题,来看看append方法浅拷贝机制,到底有什么坑!

append方法浅拷贝机制

Python中的append方法是一个常用的方法,可以将一个对象添加到列表末尾。相信大家一定都用过吧?有人去深挖这个函数的用法吗?这里面可以存在一个大坑!

我们来看一个例子:

>>> a = [1, 3, 5, "a"]
>>> b = []
>>> b.append(a)
>>> b
[[1, 3, 5, 'a']]
>>> a.append("aha")
>>> b    # surprise?
[[1, 3, 5, 'a', 'aha']]

思考一下,明明在第三行之后并没有对b操作,那么为什么b会发生改变呢?

回到今天的主题,事实上,append方法是浅拷贝。在Python中,对象赋值实际上是对象的引用,当创建一个对象,然后把它赋值给另一个变量的时候,Python并没有拷贝这个对象,而只是拷贝了这个对象的引用,这就是浅拷贝。

我们逐步来看。首先,b.append(a)就是对a进行了浅拷贝,结果为b=[[1, 3, 5, 'a']],但b[0]与a引用的对象是相同的,这可以通过id函数进行验证:

>>> id(b[0])
3145735177480
>>> id(a)
3145735177480

可见,b[0]与a指向同个内存地址。

下一步,代码执行a.append(0),列表是可变类型,这一步在原地址的列表的末尾添加0,原地址的内容被改变了但是地址没有变(可以将Python中的list理解为链表,所以这个list的地址不会变,这相当于链表的头结点),所以a和b[0]的内容同时被改变了,这就是为什么对a进行append操作b会跟着发生改变。

发生这些的前提是对同一个地址上的内容进行操作,所以影响了指向该地址的所有变量。

所以,在日常使用append函数的时候,就需要将浅拷贝变为深拷贝,有两个解决方案:

  1. b.append(list(a))

  1. b.append(a[:])

还是上面的例子,来看看这两个方法的结果是不是真的解决了append浅拷贝问题。

>>> a = [1, 3, 5, "a"]
>>> b = []
>>> b.append(list(a))
>>> b
[[1, 3, 5, 'a']]
>>> a.append(0)
>>> a
[1, 3, 5, 'a', 0]
>>> b
[[1, 3, 5, 'a']]
>>> a = [1, 3, 5, "a"]
>>> b = []
>>> b.append(a[:])
>>> b
[[1, 3, 5, 'a']]
>>> a.append(10)
>>> a
[1, 3, 5, 'a', 10]
>>> b
[[1, 3, 5, 'a']]

怎么样,问题是不是解决了!所以日常使用中,一定要避免浅拷贝带来的问题!

这个append的坑,也是我在刷leetcode:77. 组合时注意到的,题解为:

class Solution:
    def combine(self, n: int, k: int) -> List[List[int]]:
        def traversal(n, k, start_index):
            if len(path) == k:
                result.append(path[:])   # 精华在这,要解决这里的浅拷贝问题!
                return
            
            for i in range(start_index, n + 1):
                path.append(i)
                traversal(n, k, i + 1)
                path.pop()
        
        path = []
        result = []
        traversal(n, k, 1)
        return result

如果不处理第5行处的浅拷贝问题,会导致运行处下面的结果:

为啥?因为回溯呀,在上面代码的第11行处,一直在向上回溯,所以结果运行出来就变成了空列表!

所以,在刷回溯的题的时候,如果你使用的是Python,一定要注意这一点了!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/193822.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

分享158个ASP源码,总有一款适合您

ASP源码 分享158个ASP源码,总有一款适合您 下面是文件的名字,我放了一些图片,文章里不是所有的图主要是放不下..., 158个ASP源码下载链接:https://pan.baidu.com/s/1DCXBAXJUNMZZpbyxVF5-bg?pwdbwuv 提取码&#x…

react native android环境搭建,使用vscode和夜神模拟器进行开发(适用于0.68+版本)

前言 react native官网教程 使用的是android studio搭建环境,本篇文章使用vscode和夜神模拟器进行搭建环境 版本说明: 0.68.0 及以上版本直接往下看0.67.4 及以下版本请查看另一篇文章:react native android环境搭建,使用vscod…

FineReport学习-【01 帆软报表入门】

界面功能 官方管理面板详解见这里 报表简介 报表类型 报表设计流程 新建数据连接 查看数据库连接,新建一个本地mysql的数据库 新建报表 新建数据集 实例操作 实例1 分组报表 新建文件夹,用来保存报表 将刚刚查询的数据表放入报表中,并插入表…

k8s核心资源ingress

一、简介ingress是分装到service层上层的一个模块,对外提供统一访问入口,ingress底层是nginx实现的,并且分装了域名访问。外界请求首先打到ingress层,ingress再转发给service层,service再负载均衡到其中的一个pod上。i…

关于符合车规的高精度定位产品

文章目录一、什么是P-Box二、ST的P-Box三、导远的P-Box四、华测的P-Box参考来源对于导航产品来说,下一个大的市场可能就是智能驾驶/辅助驾驶,研发符合车规的导航产品也逐渐成了行业趋势。组合导航产品的主流方案是外置的P-Box方案,只需要单GN…

excel定位选取:再谈快捷键Ctrl+G的妙用

一、仅复制可见单元格在日常工作中我们经常会涉及将隐藏或分类汇总后的数据,粘到一个新表。这个时候如果我们直接复制,粘贴会发生什么呢?这是一个分类汇总后的数据,自动生成了分级显示:第1级,总计&#xff…

uniapp提交应用市场打包问题和安装应用弹出隐私政策协议问题(Android)

uni-app 安卓App提交到应用市场踩坑记录,隐私合规检测,参考链接:https://juejin.cn/post/7163595800235212830 打包问题,同时支持32位和64位;https://uniapp.dcloud.net.cn/tutorial/app-android-abifilters.html# 重…

【Android Studio】【Flutter】Android Studio下Flutter环境搭建记录

目录:1、要学flutter,必须先学Dart语言(类似C语言)2、下载Flutter SDK(软件开发工具包)3、配置国内镜像4、Android Studio新建Flutter项目5、问题解决:(运行flutter doctor命令检查问…

《流浪地球2》的冷思考:如何消除信息孤岛

硬核科幻影片《流浪地球2》成了热议焦点,网友们一方面点赞视觉特效的精益求精,另一方面为引爆月球的故事情节感动,片中一句“50岁以上的出列”让无数观众飙泪。在科技已经进步到地球能在宇宙中“流浪”的未来,仍需牺牲众多“老”宇…

ArkTS初学(一)

想必大家都听说过华为的方舟框架,没错,这就是所说的ArkTS。在HarmonyOS2的时候大家会使用java开发HarmonyOS应用,使用的是Layout来进行布局(用的还是xml文件),之后又出现了js的Component(记不清名字了)的一个功能方便了开发。我们现在就来学习HarmonyOS3…

【数据结构】ArrayList的具体使用(杨辉三角、扑克牌游戏)

目录 1、了解集合的框架 2、了解ArrayList类 2.1、认识ArrayList类当中的属性 2.1、认识ArrayList类库当中的方法 2.1.1、了解构造方法 2.2、ArrayList类当中的Add(新增元素)方法 2.3、了解ensureCapacityInternal(判断是否需要扩容&…

【Rust】18. Rust 的面向对象特性

18.1 面向对象语言的特征 18.1.1 对象:数据 行为 18.1.2 封装隐藏了实现细节 在 Rust 中,在代码中不同的部分考虑使用 pub 可以封装其实现细节 18.1.3 继承,作为类型系统与代码共享 在 Rust 中,不存在继承的机制,而…

【C++11】初始化列表、decltype操作符、nullptr

目录 一、初始化列表 1.1 花括号初始化 1.2 initializer_list 二、decltype 三、nullptr 一、初始化列表 1.1 花括号初始化 在C98中,标准允许使用花括号{ }对数组或结构体元素进行统一的列表初始值设定。 而在C11推出后,使用初始化列表时&#x…

java的方法使用

1.方法概述1.1什么是方法方法(method)是将具有独立功能的代码块组织成为一个整体,使其具有特殊功能的代码集注意:方法必须先创建才可以使用,该过程称为方法定义方法创建后并不是直接运行的,需要手动使用后才执行,该过程…

深入理解mysql性能优化以及解决慢查询问题

MySql系列整体栏目 内容链接地址【一】深入理解mysql索引本质https://blog.csdn.net/zhenghuishengq/article/details/121027025【二】深入理解mysql索引优化以及explain关键字https://blog.csdn.net/zhenghuishengq/article/details/124552080【三】深入理解mysql的索引分类&a…

GPT1、GPT2、GPT3原理

一 背景 GPT1:Generative Pre-Training。是一种生成式的预训练模型,由OpenAi团队发表自论文《Improving Language Understanding by Generative Pre-Training》。 h0=UWe+Wp 二 模型整体结构(宏观) 图1 GPT整体结构 左侧为模型的整体结构,由12个Transformer中的Decoder模块…

App的分类与简析

引言随着智能手机的普及,移动端应用几乎成为每个互联网产品的标配。在快速迭代的互联网战场中高效开发、低成本上线产品,是每个应用开发团队追求的目标。此时,选择合适的应用类型和开发模式便至关重要。移动应用可以粗分为三种:原…

Hystrix线程池隔离与接口限流

前面了解了Hystrix的请求缓存、fallback降级、circuit breaker断路器快速熔断,下面来看下Hystrix的线程池隔离与接口限流。 Hystrix通过判断线程池或者信号量是否已满,超出容量的请求,直接Reject走降级,从而达到限流的作用。限流是限制对后端服务的访问量,比如对MySQL、Re…

CentOS7 LVM 逻辑卷2种读写策略(磁盘IO性能优化)—— 筑梦之路

LVM 逻辑卷的读写策略有两种: linear:线性方式,一块块盘来读写,写完一块盘再写第二块盘、第 N 块盘,性能低striped:条带方式,多块盘一起并行读写,性能高查看 LVM 逻辑卷的读写策略的…

元宇宙,会成为下一代互联网的主场吗?

导语 | 2022 年元宇宙风靡全网,作为过去一年科技界的“当红扛把子”,引多家科技巨头“竞折腰”。近日,《福布斯》双周刊网站在报道中指出,2030 年全球元宇宙的市场规模有望高达 5 万亿美元,2023 年可能是确定其发展方向…