一文彻底理解python浅拷贝和深拷贝

目录

  • 一、必备知识
  • 二、基本概念
  • 三、列表,元组,集合,字符串,字典浅拷贝
    • 3.1 列表
    • 3.2 元组
    • 3.3 集合
    • 3.4 字符串
    • 3.5 字典
    • 3.6 特别注意
    • 可视化展示
    • 浅拷贝总结
  • 四、列表,元组,集合,字符串,字典深拷贝
    • 可视化展示
    • 结论

一、必备知识

  • 万物皆对象:在学习python的深浅拷贝之前我们必须要知道一个事情,就是python对象的引用,在python里面,万物皆对象,万物皆对象,万物皆对象,不管什么数据类型都是对象。我们定义一个变量并给这个变量赋值的时候赋的并不是这个对象值,而是这个对象引用,并不是一直值,如a = 1,这个时候并不是把1这个值赋给了a,而是把1这个对象的引用赋值给了a
  • 可变序列和不可变序列:可变序列就是可以直接对这个序列直接在原地址上进行数据修改,如果是不可变序列进行数据修改则会创建一个新的对象,让我这个变量重新指向新的对象。关于这部分不不懂的小伙伴可以参考下这篇博文:Python的可变类型与不可变类型,如果看完还是有不明白的地方可以评论区留言。

二、基本概念

  • 浅拷贝:浅拷贝会创建一个新的对象,但这个新对象的内可能是院对象的引用或者复制(视具体数据类型而言)。具体来说,如果原对象的元素是可变的(比如列表,字典,集合),浅拷贝会复制这些元素的引用,而不是元素本身。这意味着新对象和原对象会共享这些可变元素。如果对这些共享的元素进行修改,会影响到原对象。如果原对象的元素是不可变的(比如元组或字符串),浅拷贝则会复制这些元素的值,因为它们是不可变的,不会影响到原对象。浅拷贝通常有三种方式:自身构造器切片copy.copy()函数,不同数据类型(列表,元组,字典,集合 ,字符串)的浅拷贝会有差异,下面会逐一介绍。

  • 深拷贝:重新分配一块新的内存,创建一个新的对象,并将原对象中的元素以递归的方式通过创建新的子对象拷贝到新的对象中。新的对象和原对象之间没有任何关系。深拷贝使用copy.deepcopy()函数实现

  • python自带数据类型: 列表,元组,字典,集合,字符串

  • 必备工具网站:pythontutor

三、列表,元组,集合,字符串,字典浅拷贝

3.1 列表

  • 自身构造器:
>>> list1 = [1,2,3,4]
>>> list2 = list(list1)
>>> list2
[1, 2, 3, 4]
>>> id(list1)
140495553055488
>>> id(list2)
140495553080256
>>> list1==list2
True
  • 切片
>>> list1 = [1,2,3,4]
>>> list2 = list1[:]
>>> list2
[1, 2, 3, 4]
>>> list1 is list2
False
>>> list1 == list2
True
  • copy()函数
>>> import copy
>>> list1 = [1,2,3,4]
>>> list2 = copy.copy(list1)
>>> list1
[1, 2, 3, 4]
>>> list2
[1, 2, 3, 4]
>>> list1 is list2
False
>>> list1 == list2
True

注:python中的可变序列有自己的copy()方法,即对于列表和字典这种的对象可以使用list.copy()或者dict.copy()跟copy.copy()函数是等价的。

  • 总结:python列表可以使用三种方式进行浅拷贝:自身构造器,切片,copy()函数。浅拷贝之后两个变量的地址不一样,但是数值是一样的,

3.2 元组

  • 自身构造器
>>> a = (1,2,3,4)
>>> b = tuple(a)
>>> a
(1, 2, 3, 4)
>>> b
(1, 2, 3, 4)
>>> a is b
True
>>> a == b
True
  • 切片
>>> a = (1,2,3,4)
>>> b = a[:]
>>> a is b
True
>>> a == b
True
>>> a
(1, 2, 3, 4)
>>> b
(1, 2, 3, 4)
  • copy函数
>>> import copy
>>> a = (1,2,3,4)
>>> b = copy.copy(a)
>>> a
(1, 2, 3, 4)
>>> b
(1, 2, 3, 4)
>>> a is b
True
>>> a == b
True

3.3 集合

  • 自身构造器
>>> a = {1,2,3,4}
>>> b = set(a)
>>> a
{1, 2, 3, 4}
>>> b
{1, 2, 3, 4}
>>> a is b
False
>>> a == b
True
  • copy函数()
>>> import copy
>>> a = {1,2,3,4}
>>> b = copy.copy(a)
>>> a
{1, 2, 3, 4}
>>> b
{1, 2, 3, 4}
>>> a is b
False
>>> a ==b
True

3.4 字符串

  • 自身构造器
>>> a = "1234"
>>> b = str(a)
>>> a
'1234'
>>> b
'1234'
>>> a is b
True
>>> a == b
True
  • 切片
>>> a = "1234"
>>> b = a[:]
>>> a
'1234'
>>> b
'1234'
>>> a is b
True
>>> a == b
True
  • copy()
>>> import copy
>>> a = "1234"
>>> b = copy.copy(a)
>>> a
'1234'
>>> b
'1234'
>>> a is b
True
>>> a ==b
True

3.5 字典

  • 自身构造器
>>> dict1 = {"a":1, 1:2}
>>> dict2 = dict(dict1)
>>> dict1
{'a': 1, 1: 2}
>>> dict2
{'a': 1, 1: 2}
>>> dict1 is dict2
False
>>> dict1 == dict2
True
  • copy函数
>>> import copy
>>> dict1 = {"a":1, 1:2}
>>> dict2 = copy.copy(dict1)
>>> dict1
{'a': 1, 1: 2}
>>> dict2
{'a': 1, 1: 2}
>>> dict1 is dict2
False
>>> dict1 == dict2
True

3.6 特别注意

>>> list1 = [[1, 2], (30, 40)]
>>> list2 = list(list1)
>>> list1.append(100)
>>> list1
[[1, 2], (30, 40), 100]
>>> list2
[[1, 2], (30, 40)]
>>> list1[0].append(3)
>>> list1
[[1, 2, 3], (30, 40), 100]
>>> list2
[[1, 2, 3], (30, 40)]
>>> list1[1] += (50,60)
>>> list1
[[1, 2, 3], (30, 40, 50, 60), 100]
>>> list2
[[1, 2, 3], (30, 40)]
  • 如果是可变类型,浅拷贝之后一个变量改变不会影响到另一个,但是如果是不可变类型,一个改变了会影响到另一个同时改变。

可视化展示

  • 可变类型
list1 = [1,2,[3,4,[5,6]]]
list2 = list(list1)dict1 = {"a":111, "b":{"c":222, "d":{"e":333}}}
dict2 = dict(dict1)set1 = {1,2,3,4}
set2 = set(set1)

内存指向:
在这里插入图片描述

  • 可变和不可变
list1 = [1,2,[3,4, [5,6]]]
list2 = list1
list3 = list(list1)
print(id(list1))
print(id(list2))
print(id(list3))tuple1 = (1,2,(3,4,(5,6)))
tuple2 = tuple(tuple1)
tuple3 = tuple1 + (7,8)
tuple4 = tuple1
tuple5 = tuple1[1:3]
print(id(tuple1))
print(id(tuple2))
print(id(tuple3))str1 = "12'34'56''"
str2 = str1[1:5]
str3 = str1
str4 = str1[:]
print(id(str1))
print(id(str2))
print(id(str3))
print(id(str4))a = 135346347458484
b = int(a)
b = 123

输出:

140007835258880
140007835258880
140007835581440
140007674106368
140007674106368
140007674089280
140007835585072
140007660015344
140007835585072
140007835585072

内存指向
在这里插入图片描述

浅拷贝总结

  • 可变数据类型的浅拷贝就是为新的变量重新分配一块内存空间,和原来变量的内存不一样,但是变量的值是一样的
  • 不可变数据类型不会发生浅拷贝,只是开辟了内存存储原对象的引用,而不是存储原对象的子对象的引用。
  • 要与赋值操作区分,赋值只是把原对象的引用赋值给了新的变量,相当于这两个变量指向同一个对象
  • 浅拷贝只改改变最外面一层的元素不会影响到原始数据(也就是最外层的数据是复制),改变内层元素则会影响原始数据(内层数据是引用)。
  • 可变类型会重新开辟一段内存,最外层元素互不影响,内层元素会指向原始的数据。不可变类型的数据发生完全浅拷贝(这里为了方便介绍理解成浅拷贝,实际上不可变类型不是浅拷贝,数据全部复制)时,新的变量和原始的变量的地址是一模一样的,如果是发生部分数据的复制或者增加数据的时候,则会新开辟一段空间。
  • 我们重点关注可变类型,因为不可变类型即使发生了浅拷贝或者赋值对我们后续使用没有任何影响,因为不可变类型数据不能被修改,一旦修改就重新开辟了一个新的内存来存储。

四、列表,元组,集合,字符串,字典深拷贝

可视化展示

  • 代码
import copy
list1 = [1,2,[3,4, [5,6]]]
list2 = copy.deepcopy(list1)
print(id(list1))
print(id(list2))tuple1 = (1,2,(3,4,(5,6)))
tuple2 = copy.deepcopy(tuple1)
print(id(tuple1))
print(id(tuple2))tuple3 = (1,2,[3,4], {"a":1})
tuple4 = tuple(tuple3)
tuple4[2].append(5)
tuple4[3]["a"] = 2

输出:

140347510384064
140347510378496
140347334201984
140347334201984
  • 可视化
    在这里插入图片描述

结论

  • 可变类型深拷贝之后新旧变量地址不一样,不可变类型不变

  • 元组类型比较特殊, 元组内部如果嵌套了 可变类型(list, dict)浅拷贝之后, 内部的值修改, 会影响拷贝之后的结果

  • 补充:函数传参的时候不可变类型是值传递,可变类型是传引用

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

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

相关文章

Python爬虫实战(六)——使用代理IP批量下载高清小姐姐图片(附上完整源码)

文章目录 一、爬取目标二、实现效果三、准备工作四、代理IP4.1 代理IP是什么?4.2 代理IP的好处?4.3 获取代理IP4.4 Python获取代理IP 五、代理实战5.1 导入模块5.2 设置翻页5.3 获取图片链接5.4 下载图片5.5 调用主函数5.6 完整源码5.7 免费代理不够用怎…

【UE 模型描边】UE5中给模型描边 数字孪生 智慧城市领域 提供资源下载

目录 0 引言1 Soft Outlines1.1 虚幻商城1.2 使用步骤 2 Auto Mesh Outlines2.1 虚幻商城2.2 使用步骤 3 Survivor Vision3.1 虚幻商城3.2 使用步骤 结尾 🙋‍♂️ 作者:海码007📜 专栏:UE虚幻引擎专栏💥 标题&#xf…

多线程---JUC

文章目录 什么是JUC?Callable接口ReentrantLockReentrantLock VS synchronized 原子类线程池信号量SemaphoreCountDownLatch 什么是JUC? JUC是:java.util.concurrent这个包名的缩写。它里面包含了与并发相关,即与多线程相关的很多…

【NeurIPS 2023】多模态联合视频生成大模型CoDi

Diffusion Models视频生成-博客汇总 前言:目前视频生成的大部分工作都是只能生成无声音的视频,距离真正可用的视频还有不小的差距。CoDi提出了一种并行多模态生成的大模型,可以同时生成带有音频的视频,距离真正的视频生成更近了一步。相信在不远的将来,可以AI生成的模型可…

C++ 指针

*放在哪里? 如果声明一个变量:int* b; 如果声明多个变量:int a,*b,*c; nullptr c11中NULL的变形,是一个特殊值,可以赋给任意类型的指针,代表该指针指向为空。 this指针 this指针不是一个const Test*(…

关于ABB 机器人多任务的建立

关于ABB 机器人多任务的建立.需要实时监控某一区域,或者某一信号,或者计件到达某一数量机器人自动停止报警,显示到示教器上,多任务可以实现,类似发那科机器人后台逻辑指令 当软件选项漏选或者少选可以选择修改选项&…

新恶意软件使用 MSIX 软件包来感染 Windows

人们发现,一种新的网络攻击活动正在使用 MSIX(一种 Windows 应用程序打包格式)来感染 Windows PC,并通过将隐秘的恶意软件加载程序放入受害者的 PC 中来逃避检测。 Elastic Security Labs 的研究人员发现,开发人员通常…

pycharm使用ssh连接远程jupyter

1. 安装jupyter pip install jupyter2. 生成jupyter_notebook_config.py文件 jupyter notebook --generate-config3. 设置命令参数 jupyter notebook --no-browser --allow-root --port 8900配置Jupyter服务器 将上面的代码复制到命令行实参中:

【3D 图像分割】基于 Pytorch 的 VNet 3D 图像分割7(数据预处理)

在上一节:【3D 图像分割】基于 Pytorch 的 VNet 3D 图像分割6(数据预处理) 中,我们已经得到了与mhd图像同seriesUID名称的mask nrrd数据文件了,可以说是一一对应了。 并且,mask的文件,还根据结…

Qt使用QWebEngineView一些记录

1.关闭软件警告: Release of profile requested but WebEnginePage still not deleted. Expect troubles! 原因,系统退出关闭view,没有释放page。 解决办法:手动释放page 顺便把view也释放了。 Widget::~Widget() {updateIni…

设计模式_状态模式

状态模式 介绍 设计模式定义案例问题堆积在哪里解决办法状态模式一个对象 状态可以发生改变 不同的状态又有不同的行为逻辑游戏角色 加载不同的技能 每个技能有不同的:攻击逻辑 攻击范围 动作等等1 状态很多 2 每个状态有自己的属性和逻辑每种状态单独写一个类 角色…

力扣第509题 斐波那契数 新手动态规划(推荐参考) c++

题目 509. 斐波那契数 简单 相关标签 递归 记忆化搜索 数学 动态规划 斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是: F(0) 0&a…

git本地搭建服务器[Vmware虚拟机访问window的git服务器]

先按照https://zhuanlan.zhihu.com/p/494988089说明下载好Gitblit然后复制到tomcat的webapps目录下,如下: 双击"startup.bat"启动tomcat: 然后访问"http://127.0.0.1:8080/gitblit/"即可看到git的界面: 说明git服务器已经能够成功运行了! Vmware虚拟机…

k8s基本操作命令

目录 1、//查看资源对象简写 2、//查看集群信息 3、//配置kubectl自动补全 4、//node节点查看日志 5、//查看 master 节点状态 6、//查看命令空间 7、//查看default命名空间的所有资源 8、//创建命名空间app 9、//删除命名空间app 10、//在命名空间kube-public 创建…

Java电商平台 - API 接口设计之 token、timestamp、sign 具体架构与实现|电商API接口接入

一:token 简介 Token:访问令牌access token, 用于接口中, 用于标识接口调用者的身份、凭证,减少用户名和密码的传输次数。一般情况下客户端(接口调用方)需要先向服务器端申请一个接口调用的账号,服务器会给出一个appId和一个key, …

Android jetpack : Navigation 导航 路由 、 单个Activity嵌套多个Fragment的UI架构方式

Android Navigation 如何动态的更换StartDestination &&保存Fragment状态 Navigation(一)基础入门 google 官网 : Navigation 导航 路由 讨论了两年的 Navigation 保存 Fragment 状态问题居然被关闭了 Navigation是一种导航的概念,即把Activ…

anaconda+tensorflow安装完整步骤【亲测可用】

anacondatensorflow安装完整步骤 anaconda安装tensorflow1.安装anaconda2.下载windows版本进行下载并安装3.打开Anaconda Prompt4. 安装tensorflow PyCharm下载与安装1.官网下载pycharm社区版2.PyCharm环境配置3.测试 anaconda安装tensorflow 1.安装anaconda 官网下载anacond…

常用排序算法的理解

1.插入排序 插入排序的思想是将一个记录插入到已经排好序的有序表中,从而形成一个新的、记录数加1的有序表。在其实现过程使用双层循环,外层循环是进行插入的次数(也可以理解为比较的轮数),内层循环是当前记录查找插入…

centos部署tomcat

Java Downloads | Oracle 上面是下载网址 Tomcat是由Apache开发的一个Servlet容器,实现了对Servlet和JSP的支持,并提供了作为Web服务器的一些特有功能,如Tomcat管理和控制平台,安全域管理和Tomcat阀 简单来说:Tomcat…

Django之登录注册

最近在准备上线一个网站(基于django的编程技术学习与外包服务网站),所以会将自己的在做这个项目的过程中遇到的模块业务以及所涉及到的部分技术记录在CSDN平台里,一是希望可以帮到有需要的同学,二十以供自己后续回顾学…