深拷贝和浅拷贝(copy和deepcopy)详解

article/2025/9/17 4:27:22

深拷贝和浅拷贝(copy和deepcopy)详解

  • 详细解释
    • 存储方式
    • 列表的增删改
      • 列表修改已有值
      • 列表新增一个值
      • 列表整体重新赋值
    • copy与deepcopy的区别
    • 不可变类型
    • 可变类型

浅拷贝指的是创建一个新对象,其中包含原始对象的引用(指针),并没有真正将原始对象的数据复制到新对象中,因此新对象与原始对象共享部分或全部数据。

深拷贝指的是创建一个新对象,并递归地将原始对象的数据复制到新对象中,因此新对象与原始对象之间不存在数据共享。

区别:

  1. 对于不可变对象,浅拷贝和深拷贝没有区别,因为不可变对象的数据是无法被修改的,因此不存在共享数据的问题;
  2. 对于可变对象,浅拷贝会创建一个新对象,其中包含原始对象的引用,因此新对象与原始对象共享数据;而深拷贝会递归地创建新对象,并将原始对象的数据复制到新对象中,因此新对象与原始对象之间不存在数据共享。
import copy# a = () # 不可变类型
a = []  # 可变类型
print(id(a))
aa = copy.copy(a)
print(id(aa))
aaa = copy.deepcopy(a)
print(id(aaa))

详细解释

存储方式

首先了解一下Python的变量在内存中的存储方式。在基本数据类型中(包括set、list(tuple, str)、dict)都是采用引用的方式。

也就是说,每个变量都存储的是这个变量的地址,而不是值本身,就算更复杂的嵌套结构,也是存储是每个元素的地址而已,用一幅图来表示。

在这里插入图片描述
如上图所示,用户看到的是 lista的4个元素值,但是内存中保存的却是4个元素地址。

当元素是列表时,第一层保存的是列表的地址,第二层保存的是列表元素的地址,第三层才是列表的值。当元素是字典的时候,与列表类似。

列表的增删改

在明白了变量存储方式后,继续看下内存下的增删改是怎么变化的。

列表修改已有值

新增一个内存块,再将引用的地址修改为新内存块的地址。
在这里插入图片描述

列表新增一个值

新增一个内存块,新增一个地址引用。
在这里插入图片描述

列表整体重新赋值

删除变量地址和引用的值,新增地址和引用值的内存块。
在这里插入图片描述

copy与deepcopy的区别

  • copy:不管多么复杂的数据结构,浅拷贝都只会copy第一层。
  • deepcopy:拷贝全部数据,将整个变量内存全部复制一遍,新变量与原变量没有任何关系。

举例:

import copya = [1, 2, 3, 4, ['a', 'b']]
b = a
c = copy.copy(a)
d = copy.deepcopy(a)a.append(5)
a[1] = 20
a[4].append('c')
del a[0]print(a) # [20,3,4,['a','b','c'],5]
print(b) # [20,3,4,['a','b','c'],5]
print(c) # [1,2,3,4,['a','b','c']]
print(d) # [1,2,3,4,['a','b']]

列表b:

表示b也引用的a的地址,两者引用的内存地址是一样的。因此b和a的关系是紧密相连的,一模一样。可以通过 id(a) 和id(b)比较,两者是一样的。

列表c:

由于c是浅拷贝的a列表,因此只copy了第一层,也就是地址层。所以,

  1. 当a.append(5)时,新增了一个内存块,但是c只有前5个内存块,因此c没有变化。
  2. 继续a修改了a[1],然而这个值是属于第一层,已经copy给了c,因此c也没有变化。
  3. 继续a修改了子列表,这个时候a复制给c的只是列表的地址,且a中的子列表地址和c中的子列表地址是指向同一个地方的,因此修改了a中子列表,c中的子列表也会相应的改变。
  4. 最后删除a[0],与修改a[1]一致,与c无关。可以用图再说明一下。

在这里插入图片描述
列表d:

由于d是深拷贝的a列表,因此d是将a的地址和值一并复制过来,与a没有半点关系,也就是说d和a是两个完全独立的内存块,没有任何交集。因此,后面a的任意修改都与d无关。

在这里插入图片描述

不可变类型

在 Python 中,不可变类型是指一旦创建就不能修改其值的数据类型。Python 中常见的不可变类型包括:

  1. 数值类型(int、float、complex);
  2. 字符串类型(str);
  3. 元组类型(tuple);
  4. 布尔类型(bool)。

不可变类型的特点是一旦创建,其值就不可被修改。因此,对于不可变类型的操作通常都是创建新的对象,并返回其引用,而不是修改原来的对象。

可变类型

在 Python 中,可变类型是指其值可以被修改的数据类型。Python 中常见的可变类型包括:

  1. 列表类型(list);
  2. 字典类型(dict);
  3. 集合类型(set)。

可变类型的特点是其值可以被修改。因此,对于可变类型的操作通常都是在原对象上进行修改,而不是创建新的对象。

参考:


http://chatgpt.dhexx.cn/article/gK4v4Z3c.shtml

相关文章

浅拷贝和深拷贝的区别?

创建Java对象的方式包括new、反射、反序列化、拷贝,那么什么是拷贝呢?浅拷贝和深拷贝又有什么区别呢? 什么是拷贝 拷贝就是为了复用原对象的部分或全部数据,在原对象的基础上通过复制的方式创建一个新的对象。 Object类中有nati…

深拷贝和浅拷贝的区别

首先,明确一点深拷贝和浅拷贝是针对对象属性为对象的,因为基本数据类型在进行赋值操作时(也就是拷贝)是直接将值赋给了新的变量,也就是该变量是原变量的一个副本,这个时候你修改两者中的任何一个的值都不会…

浅拷贝与深拷贝的区别

浅拷贝与深拷贝 一、数据类型 数据分为基本数据类型(String, Number, Boolean, Null, Undefined,Symbol)和对象数据类型。 基本数据类型的特点:直接存储在栈(stack)中的数据 引用数据类型的特点:存储的是该对象在栈中引用,真实的…

堆、栈和队列

1. 堆 堆是在程序运行时,而不是在程序编译时,申请某个大小的内存空间。即动态分配内存,对其访问和对一般内存的访问没有区别。堆是指程序运行时申请的动态内存,而栈只是指一种使用堆的方法(即先进后出)。 2. 栈(stack&…

堆、栈和队列的区别

目录 数据结构中的堆、栈和队列 内存申请中的堆和栈 一个C/C程序占用的内存如下: 申请内存后的响应 申请大小的限制 申请效率的比较 堆和栈中的存储内容 数据结构中的堆、栈和队列 堆:堆是一种经过排序的树形数据结构,每个结点都有…

栈和队列

文章目录 栈栈操作队列队列操作双端队列双端队列操作 栈 栈(stack),有些地方称为堆栈,是一种容器,可存入数据元素、访问元素、删除元素,它的特点在于只能允许在容器的一端(称为栈顶端指标&…

栈和队列简介

栈和队列简介 栈和队列是两种常用的数据结构,它们的数据是按线性结构存储的,因此,栈和队列也属于线性表。 栈和队列的数据可以存储在一个顺序表里,也可以存储在一个链表里,只要满足线性存储结构就行。只对数据的线性…

栈和队列基本操作

栈和队列 一、栈栈是什么栈的实现栈的基本操作栈类型的定义初始化栈检查栈是否为满入栈出栈获取栈顶元素检测栈是否为空测试函数 完整代码Stack.hStack.cmain.c 二、队列队列是什么队列的实现队列类型的定义申请一个节点初始化队列队尾入队列队头出队列获取队列头部元素获取队列…

C#队列和栈的使用

一、队列 队列是其元素以先进先出&#xff08;Firstin,Firstout,FIFO&#xff09;的方式来处理的集合。先放入队列中的元素会先读取。队列使用System.Collections.Generic命名空间中的泛型类Queue<T>实现。 队列的成员 Count&#xff1a;Count属性返回队列中元素个数。…

栈和队列经典面试题

目录 1、括号匹配问题 2、用队列实现栈 3、用栈实现队列 4、设计循环队列 1、括号匹配问题 链接直达&#xff1a; 有效的括号 题目&#xff1a; 思路&#xff1a; 做题前&#xff0c;得先明确解题方案是啥&#xff0c;此题用栈的思想去解决是较为方便的&#xff0c;栈明确指…

栈stack和队列

栈和队列 一 栈和队列二 栈三.队列 一 栈和队列 栈和队列是两种重要的线性结构。从数据结构来看&#xff0c;栈和队列也是线性表&#xff0c;其特殊性在于栈和队列的基本操作是线性表操作的子集&#xff08;也具有顺序结构和链式结构&#xff09;&#xff0c;它们是操作受限的…

链表,队列和栈的区别

链表&#xff0c;队列和栈都是数据结构的一种。Sartaj Sahni 在他的《数据结构、算法与应用》一书中称&#xff1a;“数据结构是数据对象&#xff0c;以及存在于该对象的实例和组成实例的数据元素之间的各种联系。这些联系可以通过定义相关的函数来给出。”他将数据对象&#x…

栈与队列的定义与区别

1、栈 首先&#xff0c;普通的线性表实现是有两个端口可以访问的&#xff0c;但是如果作为栈就要封闭一端&#xff0c;只能访问另一端。这当然不是自讨苦吃&#xff0c;栈是一种抽象数据结构&#xff0c;是对现实世界对象的模拟。比如&#xff0c;自助餐厅中的一叠盘子&#x…

java 队列和栈的区别

栈和队列的区别 &#xff08;1&#xff09;数据插入删除 栈是一种特殊的线性表&#xff0c;他只能在一段进行插入和删除操作&#xff0c;就好像是一个井一样。进行数据插入和删除就类似于井口&#xff0c;称为栈定。而井也是有底部的&#xff0c;栈无法进行插入删除操作的这一…

监督学习和无监督学习的区别(机器学习)

机器学习主要分为两类 监督学习无监督学习 两者的区别主要是是否需要人工参与数据结果的标注 监督学习&#xff1a;教计算机如何去完成预测任务&#xff08;有反馈&#xff09;&#xff0c;预先给一定数据量的输入和对应的结果即训练集&#xff0c;建模拟合&#xff0c;最后让…

简单说下有监督学习和无监督学习的区别

简单说下有监督学习和无监督学习的区别 解析&#xff1a; 有监督学习&#xff1a;对具有标记的训练样本进行学习&#xff0c;以尽可能对训练样本集外的数据进行分类预测。&#xff08;LR,SVM,BP,RF,GBDT&#xff09; 无监督学习&#xff1a;对未标记的样本进行训练学习&#xf…

一个简单的例子来理解监督学习和非监督学习及其区别

首先&#xff0c;必须理解两个基本概念&#xff1a;特征值和目标值&#xff0c;先看图例 1、特征值&#xff1a; 特征值是指数据的特征&#xff0c;对于每个样本&#xff0c;通常具有一些 "属性"&#xff08;Attribute&#xff09;或者说 ”特征“&#xff08;Featu…

监督学习、无监督学习和半监督学习区别

1、概念 1.1监督学习&#xff08;数据集有输入和输出数据&#xff09;&#xff1a;通过已有的一部分输入数据与输出数据之间的相应关系。生成一个函数&#xff0c;将输入映射到合适的输出&#xff0c;比如分类。 1.2无监督学习&#xff08;数据集中只有输入&#xff09;&…

监督、自监督、半监督、无监督学习的区别

目录 一、简易版区别 二、详细版区别 一、简易版区别 A Survey on Semi-, Self-and Unsupervised Learning for Image Classification 文中的解释&#xff1a; 监督学习&#xff08;a&#xff09;&#xff1a;给出全部样本红蓝两类的标签 半监督学习&#xff08;b&#xf…

有监督学习与无监督学习

机器学习的常用方法&#xff0c;主要分为有监督学习(supervised learning)和无监督学习(unsupervised learning)。简单的归纳就是&#xff0c;是否有监督&#xff08;supervised&#xff09;&#xff0c;就看输入数据是否有标签&#xff08;label&#xff09;。输入数据有标签&…