首页 > 编程语言 >【3.0】Python中级之深浅拷贝

【3.0】Python中级之深浅拷贝

时间:2023-11-19 19:14:03浏览次数:42  
标签:Python list 列表 对象 3.0 拷贝 copy original

【一】深浅拷贝问题引入

  • 无论深拷贝还是浅拷贝都是用来 复制对象的

  • 如果是浅copy,只会复制一层,如果copy的对象中有可变数据类型,修改可变数据类型还会影响拷贝的对象

  • 如果是深copy,完整复制,无论可变或不可变,都是创建出新的来,以后再改原对象,都不会对copy出的对象造成影响

  • 在Python中,深拷贝和浅拷贝是用于复制对象的两种不同的方式。

list_original = [1, 2, 3, [4, 5, 6, ]]
list_copy = list_original
print(list_copy is list_original)
# True
  • 通过将list_copy赋值为list_original,实际上是将list_copylist_original指向相同的内存地址。
  • 所以list_copy is list_original的结果为True,表示它们是同一个对象的两个引用。
  • 因此对list_copylist_original的修改都会影响到另一个。

【1】浅拷贝

  • 浅拷贝仅复制对象的一层内容,如果对象中包含了可变数据类型(如列表、字典等),则拷贝的对象将与原对象共享这些可变数据类型的引用。
  • 这意味着对于原对象中的可变数据类型进行修改操作时,拷贝的对象也会受到影响。
import copy

# 原对象
original_list = [1, 2, [3, 4]]
# 使用浅拷贝创建拷贝对象
copied_list = copy.copy(original_list)

# 修改原对象中的可变数据类型
original_list[2].append(5)

print("原对象:", original_list)
print("拷贝对象:", copied_list)
  • 可以看到,尽管只修改了原对象中的可变数据类型(子列表),但拷贝对象也被修改了。
  • 这是因为浅拷贝仅复制了列表的第一层,而对于内部的子列表,拷贝对象和原对象共享同一个引用。
from copy import copy

list_original = [1, 2, 3, [4, 5, 6, ]]

# 使用`copy()`函数进行浅拷贝时,创建了一个新的列表对象`list_copy_two`,并复制了原始列表`list_original`中的元素。
# 这意味着`list_copy_two`和`list_original`是两个独立的对象,分别指向不同的内存地址。
list_copy_two = copy(list_original)

# 对于嵌套的可变对象(如列表),浅拷贝只会复制其引用,而不会创建新的内存空间。
print(list_copy_two is list_original)
# False

# 因此,`list_copy_two`中的嵌套列表仍然指向相同的地址
# 所以对`list_copy_two`中嵌套的列表进行修改 , 也会影响到原始的列表`list_original`。
list_copy_two[3][1] = 999
print(list_original)
# [1, 2, 3, [4, 999, 6]]
print(list_copy_two)
# [1, 2, 3, [4, 999, 6]]
  • 使用copy()函数进行浅拷贝时
    • 创建了一个新的列表对象list_copy_two,并复制了原始列表list_original中的元素。
    • 这意味着llist_copy_twolist_original是两个独立的对象,分别指向不同的内存地址。
  • 然而,对于嵌套的可变对象(如列表)
    • 浅拷贝只会复制其引用
    • 而不会创建新的内存空间。
  • 因此,list_copy_two中的嵌套列表仍然指向相同的地址
    • 所以对list_copy_two中嵌套的列表进行修改
    • 也会影响到原始的列表list_original

(2)深拷贝

  • 深拷贝会创建一个完全独立的新对象,包括所有的嵌套对象。
  • 无论原对象的数据类型是可变还是不可变,深拷贝都会创建出新的对象,以后对原对象的修改不会影响到拷贝对象。
  • 以下是一个使用深拷贝的案例:
import copy

# 原对象
original_list = [1, 2, [3, 4]]
# 使用深拷贝创建拷贝对象
copied_list = copy.deepcopy(original_list)

# 修改原对象中的可变数据类型
original_list[2].append(5)

print("原对象:", original_list)
print("拷贝对象:", copied_list)
  • 可以看到,尽管修改了原对象中的可变数据类型,但拷贝对象保持不变。
  • 这是因为深拷贝创建了一个原对象完全独立的新对象,包括了所有嵌套对象的复制。
from copy import deepcopy

list_original = [1, 2, 3, [4, 5, 6, ]]
list_deep_copy = deepcopy(list_original)
list_deep_copy[3][1] = 888
print(list_original)
# [1, 2, 3, [4, 5, 6]]
print(list_deep_copy)
# [1, 2, 3, [4, 888, 6]]
  • 通过使用deepcopy()函数进行深拷贝,会递归地复制嵌套对象,包括嵌套列表。
  • 这意味着在深拷贝操作中不仅会创建一个新的顶层列表对象list_deep_copy,还会创建一个新的嵌套列表对象,并且其值与原始列表中的值相同。
  • 因此在对list_deep_copy中的嵌套列表进行修改时,并不会影响到原始的列表list_original,它们指向不同的内存地址。

(3)小结

  • 综上所述
    • 浅拷贝只复制顶层对象
    • 而深拷贝会递归复制整个对象结构。
  • 在涉及到可变对象嵌套的情况下
    • 深拷贝是一种更安全的选项
    • 因为它可以确保对新对象的修改不会影响原始对象。

【二】深浅拷贝问题详解

  • 深拷贝和浅拷贝是常用的操作,它们在处理对象和数据结构时非常有用。
  • 让我们详细解释深拷贝和浅拷贝的概念,并结合案例进行演示。

(1)深拷贝:

  • 深拷贝是指创建一个新的对象,该对象与原始对象完全独立。
  • 换句话说,它会递归地复制所有嵌套对象,包括它们的内容,以便我们在修改新对象时不会影响到原始对象。
  • 下面是一个示例
    • 演示了如何使用copy模块中的deepcopy()函数进行深拷贝:
import copy

list1 = [1, 2, [3, 4]]
list2 = copy.deepcopy(list1)
  • 在这个例子中,我们创建了一个列表list1,其中包含一个嵌套列表。
  • 通过调用deepcopy()函数并将list1作为参数传递给它,我们可以创建一个名为list2的新对象,它是list1的深拷贝。
  • 现在,我们来演示深拷贝是如何避免原始对象的修改的:
list2[0] = 999
print(list1)  # 输出: [1, 2, [3, 4]]
print(list2)  # 输出: [999, 2, [3, 4]]
  • 可以看到,尽管我们修改了list2的第一个元素,但list1保持不变。
  • 这是因为list1list2是独立的对象,它们各自占用着不同的内存空间。

(2)浅拷贝:

  • 浅拷贝是指创建一个新对象,并将原始对象的元素复制到新对象中。
  • 然而
    • 如果原始对象包含可变的对象(如列表)
    • 则新对象中的这些元素仍然与原始对象中相应元素共享相同的内存地址。
  • 下面是一个示例
    • 演示了如何使用copy模块中的copy()函数进行浅拷贝:
import copy

list1 = [1, 2, [3, 4]]
list2 = copy.copy(list1)
  • 在这个例子中
    • 我们使用copy()函数创建了list1的浅拷贝list2
  • 让我们来看一下浅拷贝在修改可变对象时的行为:
list2[0] = 999
list2[2][0] = 777
print(list1)  # 输出: [1, 2, [777, 4]]
print(list2)  # 输出: [999, 2, [777, 4]]
  • 可以看到
    • 当我们修改list2中的第一个元素时
    • 只有list2受到影响
    • list1保持不变。
  • 但是
    • 当我们修改list2中嵌套列表的元素时
    • list1也会随之改变。
  • 这是因为浅拷贝只复制了列表的引用
    • 而没有创建新的内存空间来存储嵌套列表。

(3)综上所述

  • 深拷贝和浅拷贝在处理对象和数据结构时有不同的行为:
    • 深拷贝创建一个完全独立的对象,递归地复制所有嵌套对象。
    • 浅拷贝创建一个新对象,但它共享原始对象中可变对象的引用。

标签:Python,list,列表,对象,3.0,拷贝,copy,original
From: https://www.cnblogs.com/dream-ze/p/17842408.html

相关文章

  • Linux部署Python环境
    本文使用的Linux发行版本为AlmaLinux9.264位(CentOS停止更新后的完美替代发行版本)。本文安装的Python版本为3.12.0,其他版本方法类似。准备工作更新系统。dnf-yupdate安装Python前,需确认当前系统是否已安装Python以及对应版本。不建议卸载原有Python版本,可能被应用......
  • 【5.0】Python中级之文件操作
    【一】文本处理引入应用程序运行过程中产生的数据最先都是存放于内存中的若想永久保存下来,必须要保存于硬盘中。应用程序若想操作硬件必须通过操作系统而文件就是操作系统提供给应用程序来操作硬盘的虚拟概念用户或应用程序对文件的操作,就是向操作系统发起调用,然后由操作系统......
  • 【4.0】Python中级之字符编码
    【一】文本编辑器与Python解释器原理字符串类型、文本文件的内容都是由字符组成的,但凡涉及到字符的存取,都需要考虑字符编码的问题。【1】数据存放位置所有软件都是运行硬件之上的与运行软件相关的三大核心硬件为cpu、内存、硬盘软件运行前,软件的代码及其相关数据都......
  • 【6.0】Python中级之异常处理
    【一】什么是异常异常是程序运行时可能发生的错误或意外情况。在Python中,异常是一种对象,表示程序执行期间发生的错误。当出现异常时,程序的正常流程会被中断,而是跳转到异常处理流程。【二】异常分类在Python中,异常分为两类:内建异常(Built-inExceptions):由Python内部定义......
  • 大白话说Python+Flask入门(三)
    写在前面今天状态很不好,我发现学这部分知识的时候,会出现溜号或者注意力无法集中的情况。我能想到的是,大概率是这部分知识,应该是超出了我现在的水平了,也就是说我存在知识断层了,整体感觉真的是一知半解。那有同学会问了,那你能说明白吗?我理解的肯定能呀,来往下看!Flask的使用1、......
  • 《运营之光3.0》摘录
    一家公司的商业价值=(其拥有的用户数量×平均单体用户价值)-流量营销成本-交付供给成本对于ToB,类似地:一家公司的商业价值=(其拥有的客户数量×平均单体客户价值)-成本=[其拥有的客户数量×(平均单体客户带来的GMV×佣金)]-成本行业里的一切运......
  • Python批量求取Excel表格每一个4行内某列的最大值、最小值
      本文介绍基于Python语言,基于Excel表格文件内某一列的数据,计算这一列数据在每一个指定数量的行的范围内(例如每一个4行的范围内)的区间最大值的方法。  已知我们现有一个.csv格式的Excel表格文件,其中有一列数据,我们希望对其加以区间最大值的计算——即从这一列的数据部分(也就是......
  • 洛谷B2017 打印 ASCII 码(Python3)
    要点:1.Python的input()默认要换行,而在输入的时候即使只输了一个字符,也会被判定为输入两个字符。故此处要么只取字符串的第一位,要么在输入时用.strip()来删去首位字符,strip的介绍在这里2.Python中不能用强制类型转换来得到ASCII码,需要用到ord()函数。ord():括号内的字符的ASCI......
  • 洛谷B2016 浮点数向零舍入(Python3)
    要点:1.有正有负怎么办?正负分开写?如果只看数字部分,那取整的方式是一样的。所以我们可以先输出符号,把问题全都转化到非负数集中。2.如何取整?此处取整为向下取整。而强制类型转换把浮点数转化为整型数的时候是把小数部分全部去掉,而不是四舍五入,与题中取整方式相符,故可直......
  • python之numpy处理股票数据
    一概述Numpy是一个最重要的一个基于多维数组对象,即ndarray对象,该对象具有矢量算数运算能力和复杂的广播能力,可以执行一些科学计算。它的常用属性如下表所示:属性说明ndim数组的维度,如一维、二维、三维等shape数组的形状,如一个5行4列的数组,它的shape属性为(5,4)size数组元素的总个数......