简单理解Python中的深拷贝与浅拷贝
I. 简介
深拷贝会递归的创建一个完全独立的对象副本,包括所有嵌套的对象,而浅拷贝只复制嵌套对象的引用,不复制嵌套对象本身。
简单来说就是两者都对原对象进行了复制,因此使用is运算符来比较新旧对象时,返回的都是False(都开辟了新的内存);两者区别在于对嵌套对象有没有进行递归的复制。浅拷贝没有给嵌套对象复制并分配新内存,用is来比较嵌套对象时返回的是True;而深拷贝对嵌套对象开辟了进行了复制并分配新内存,用is来比较嵌套对象时返回的是False。
一个例子如下,我们分别对链表的头结点执行深拷贝与浅拷贝:
# 原链表 ↓
a1 -> b1 -> c1 -> d1 -> e1
# 浅拷贝 ↓ 对于嵌套对象b1, c1, ..., 直接采用了原有引用
a2 -> b1 -> c1 -> d1 -> e1
# 深拷贝 ↓ 对于嵌套对象,同样开辟了内存空间将其复制
a2 -> b2 -> c2 -> d2 -> e2
从代码实现来讲,深拷贝可以用copy库的deepcopy方法实现;浅拷贝除了用copy库的copy方法,还有许多其他的实现途径,接下来我们将进行介绍。
II. 列表
A. 首先要注意一点,对于常用的等号赋值操作,这一操作并没有进行任何拷贝,只是创建了对现有对象的一个新引用:
arr1 = [1, 2, 3, 4]
arr2 = arr1
print(arr2 is arr1) # True
arr2[0] = 0
print(arr1) # [0, 2, 3, 4]
B. 对列表进行切片属于浅拷贝操作:
arr1 = [1, 2, 3, 4]
arr2 = arr1[:]
print(arr2 is arr1) # False
arr2[0] = 0
print(arr1) # [1, 2, 3, 4]
C. 浅拷贝并不会复制嵌套对象:
arr1 = [1, 2, 3, [4, 5, 6]]
arr2 = arr1[:]
print(arr2 is arr1) # False(最外层被复制)
print(arr2[-1] is arr1[-1]) # True(嵌套对象没有被复制)
arr2[-1][0] = 0
print(arr1) # [1, 2, 3, [0, 5, 6]](被修改)
D. 深拷贝才会复制嵌套对象:
import copy
arr1 = [1, 2, 3, [4, 5, 6]]
arr2 = copy.deepcopy(arr1)
print(arr2 is arr1) # False
print(arr2[-1] is arr1[-1]) # False(嵌套对象也被复制)
arr2[-1][0] = 0
print(arr1) # [1, 2, 3, [4, 5, 6]](未修改)
E. 使用数据类型本身的构造器仍属于浅拷贝:
arr1 = [1, 2, 3, [4, 5, 6]]
arr2 = list(arr1) # 使用构造器创建新对象, 属于浅拷贝
print(arr2 is arr1) # False
print(arr2[-1] is arr1[-1]) # True
arr2[-1][0] = 0
print(arr1) # [1, 2, 3, [0, 5, 6]]
F. 对列表进行修改所返回的新列表也属于浅拷贝(先浅拷贝再修改):
arr1 = [1, 2, 3, [4, 5, 6]]
arr2 = arr1 + [] # 先浅拷贝再修改
print(arr2 is arr1) # False
print(arr2[-1] is arr1[-1]) # True
arr2[-1][0] = 0
print(arr1) # [1, 2, 3, [0, 5, 6]]
III. 字符串
A. Python中的字符串是不可变对象。因此,如果对其进行完整切片[:],可以发现这一过程并没有对字符串本身进行修改。那么Python此时只会直接记录原字符串对象的引用,不进行任何拷贝。从设计动机的角度理解,既然本身不可修改,并且进行的切片操作也没有进行修改,那么复制的意义不大,所以干脆不进行复制:
s1 = "1234"
s2 = s1[:]
print(s2 is s1) # True(引用的内容相同)
B. 以上结论同样适用于对字符串进行"假修改",此时也不会进行任何拷贝:
s1 = "1234"
s2 = s1 + ""
print(s2 is s1) # True(没有进行实质修改)
C. 想要进行拷贝,那就得对字符串进行实质修改。如果切片运算改变了原字符串的内容,由于字符串是不可变的,因此只能开辟一个新的内存,来存储修改后的字符串。此时进行了拷贝过程。注意,由于字符串本身没法嵌套对象,因此这里不区分深拷贝与浅拷贝:
s1 = "1234"
s2 = s1[::-1][::-1] # 进行两次修改,翻转两次
print(s2 is s1) # False
print(s2) # 1234
s3 = s1 + "5"
print(s3 is s1) # False
D. 使用构造方法str,也不会进行任何拷贝,只是创建了另一个指向原字符串对象的引用:
s1 = "1234"
s2 = str(s1)
print(s2 is s1) # True
E. 使用copy或deepcopy都不能对字符串内容进行拷贝,只会新增一个引用:
import copy
s1 = "1234"
s2 = copy.copy(s1)
s3 = copy.deepcopy(s1)
print(s2 is s1) # True
print(s3 is s1) # True
相关文章:
简单理解Python中的深拷贝与浅拷贝
I. 简介 深拷贝会递归的创建一个完全独立的对象副本,包括所有嵌套的对象,而浅拷贝只复制嵌套对象的引用,不复制嵌套对象本身。 简单来说就是两者都对原对象进行了复制,因此使用is运算符来比较新旧对象时,返回的都是F…...

C++之std::pair<uint64_t, size_t>应用实例(一百七十七)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…...

前端打开后端返回的HTML格式的数据
前端打开后端返回的 HTML格式 的数据: 后端返回的数据格式如下示例: 前端通过 js 方式处理(核心代码如下) console.log(回调, path); // path 是后端返回的 HTML 格式数据// 必须要存进localstorage,否则会报错&am…...
How to deal with document-oriented data
Schema designData models for e-commerceNuts and bolts of databases, collection, and documents. Principles of schema design What are your application access pattern?Whats the basic unit of data? the basic unit of data is the BSON documentWhat are the ca…...
Http 状态码汇总
文章目录 Http 状态码汇总1xx(信息性状态码)2xx(成功状态码)3xx(重定向状态码)4xx(客户端错误状态码)5xx(服务器错误状态码) Http 状态码汇总 1xx(…...
mysql自定义实体类框架
根据表结构自动生产实体类和方法,根据反射与io生成,可自定义扩展方法 package com.digital.web.front; /*** pom依赖* <dependency>* <groupId>mysql</groupId>* <artifactId>mysql-connector-java</artifactId>* <version>5.1.27</ve…...
批量将Excel中的第二列内容从拼音转换为汉字
要批量将Excel中的第二列内容从拼音转换为汉字,您可以使用Python的openpyxl库来实现。下面是一个示例代码,演示如何读取Excel文件并将第二列内容进行拼音转汉字: from openpyxl import load_workbook from xpinyin import Pinyin # 打开Exce…...
消息推送:精准推送,提升运营效果,增添平台活力
对于app开发者而言,没有什么途径比消息推送更能直接、即时地触及目标用户群体了。消息推送与我们的日常生活息息相关,各种APP的状态和通知都通过消息推送来告知用户,引起用户的注意,吸引用户点开app。总而言之,推送服务…...

[保研/考研机试] KY43 全排列 北京大学复试上机题 C++实现
题目链接: 全排列https://www.nowcoder.com/share/jump/437195121692001512368 描述 给定一个由不同的小写字母组成的字符串,输出这个字符串的所有全排列。 我们假设对于小写字母有a < b < ... < y < z,而且给定的字符串中的字…...
Java将时间戳转化为特定时区的日期字符串
先上代码: ZonedDateTime dateTime ZonedDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()),zone ); //2019-12-01T19:01:4608:00String formattedDate dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd") ); //2019-12-…...

【算法挨揍日记】day03——双指针算法_有效三角形的个数、和为s的两个数字
611. 有效三角形的个数 611. 有效三角形的个数https://leetcode.cn/problems/valid-triangle-number/ 题目描述: 给定一个包含非负整数的数组 nums ,返回其中可以组成三角形三条边的三元组个数。 解题思路: 本题是一个关于三角形是否能成立…...

通过 kk 创建 k8s 集群和 kubesphere
官方文档:多节点安装 确保从正确的区域下载 KubeKey export KKZONEcn下载 KubeKey curl -sfL https://get-kk.kubesphere.io | VERSIONv3.0.7 sh -为 kk 添加可执行权限: chmod x kk创建 config 文件 KubeSphere 版本:v3.3 支持的 Kuber…...

感觉和身边其他人有差距怎么办?
虽然清楚知识需要靠时间沉淀,但在看到自己做不出来的题别人会做,自己写不出的代码别人会写时还是会感到焦虑怎么办? 你是否也因为自身跟周围人的差距而产生过迷茫,这份迷茫如今是被你克服了还是仍旧让你感到困扰? 下…...

【C语言基础】宏定义的用法详解
📢:如果你也对机器人、人工智能感兴趣,看来我们志同道合✨ 📢:不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 📢:文章若有幸对你有帮助,可点赞 👍…...

微服务系列文章之 SpringBoot 最佳实践
Spring Boot 是一种广泛使用且非常流行的企业级高性能框架。 以下是一些最佳实践和一些技巧,我们可以使用它们来改进 Spring Boot 应用程序并使其更加高效。 Spring Boot 的四大核心 1、自动配置 针对很多Spring应用程序和常见的应用功能,Spring Boo…...
C++并发多线程--std::async、std::packaged_task和std::promise的使用
目录 1--std::async的使用 2--std::packaged_task的使用 3--std::promise的使用 1--std::async的使用 std::async用于启动一个异步任务,并返回一个std::future对象;std::future对象里含有异步任务线程入口函数的结果; std::launch::deferr…...

opencv-目标追踪
import argparse import time import cv2 import numpy as np# 配置参数 ap argparse.ArgumentParser() ap.add_argument("-v", "--video", typestr,help"path to input video file") ap.add_argument("-t", "--tracker", …...

【数据结构】 单链表面试题讲解
文章目录 引言反转单链表题目描述示例:题解思路代码实现: 移除链表元素题目描述:示例思路解析: 链表的中间结点题目描述:示例:思路解析代码实现如下: 链表中倒数第k个结点题目描述示例思路解析&…...

C++ string类的模拟实现
模拟实现string类不是为了造一个更好的轮子,而是更加理解string类,从而来掌握string类的使用 string类的接口设计繁多,故而不会全部涵盖到,但是核心的会模拟实现 库中string类是封装在std的命名空间中的,所以在模拟…...

Qt实现简单的漫游器
文章目录 Qt的OpenGL窗口GLSL的实现摄像机类的实现简单的漫游器 Qt的OpenGL窗口 Qt主要是使用QOpenGLWidget来实现opengl的功能。 QOpenGLWidget 提供了三个便捷的虚函数,可以重载,用来重新实现典型的OpenGL任务: paintGL:渲染…...

接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...

铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...