首页 > 编程语言 >python入门之深浅拷贝】---python 深浅拷贝

python入门之深浅拷贝】---python 深浅拷贝

时间:2023-12-06 19:33:22浏览次数:54  
标签:python list 列表 对象 深浅 ori 拷贝 copy

title:  【python入门之深浅拷贝】---python 深浅拷贝
date:  2023-12-06  18:54:06 
updated: 2023-12-06 19:20:00
description: 【python入门之深浅拷贝】---python 深浅拷贝
cover: https://zhuanlan.zhihu.com/p/631965597
       https://home.cnblogs.com/u/dream-ze/

【一】深浅拷贝问题引入

前言

- python常见的面试题之一:
- 无论深拷贝还是浅拷贝都是用来 复制对象的
- 如果是浅copy,只会复制一层,如果copy的对象中有可变数据类型,修改可变数据类型还会影响拷贝的对象
- 如果是深copy,完整复制,无论可变或不可变,都是创建出新的来,以后再改原对象,都不会对copy出的对象造成影响
  • 在Python中,深拷贝和浅拷贝是用于复制对象的两种不同的方式。
list_ori = [11, 12, 13, [14, 15, 16, ]]
list_copy = list_ori
print(list_copy is list_ori)
# True
  • 通过将list_copy赋值为list_ori,实际上是将list_copylist_ori指向相同的内存地址。
  • 所以list_copy is list_ori的结果为True,表示它们是同一个对象的两个引用。
  • 因此对list_copylist_ori的修改都会影响到另一个。
    image

【1】浅拷贝

定义

浅拷贝是指创建一个新对象,但是这个新对象只是原始对象的一个引用。也就是说,在新对象中,原始对象中的所有元素都只是引用。如果原始对象中的元素发生了变化,那么新对象中的元素也会发生变化。

使用及示例:

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

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

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

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

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

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

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

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

(2)深拷贝

定义

深拷贝是指创建一个新对象,并且这个新对象与原始对象没有任何关联。也就是说,在新对象中,原始对象中的所有元素都被复制到了新的内存地址中。如果原始对象中的元素发生了变化,那么新对象中的元素不会受到影响。

使用及示例

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

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

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

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

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

注意

在使用深拷贝时,需要注意以下几点:

深拷贝可能会比较耗时,因为它需要递归地复制整个对象树。
深拷贝可能会导致循环引用的问题。如果被复制的对象中存在循环引用,那么深拷贝会进入死循环,直到Python的最大递归深度被达到为止。
深拷贝可能会导致内存占用过高的问题。如果被复制的对象非常大,那么深拷贝会占用大量的内存。
综上所述,深浅拷贝是Python中非常重要的概念,对于理解Python中的内存管理和对象模型非常有帮助。在实际开发中,我们需要根据具体的情况选择使用哪种方法,并且需要注意深拷贝可能带来的性能和内存问题。

(3)小结

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

浅拷贝创建一个新对象,但是这个新对象只是原始对象的一个引用;而深拷贝创建一个新对象,并且这个新对象与原始对象没有任何关联。在实际开发中,我们需要根据具体的情况选择使用哪种方法。

如果我们需要复制的对象只包含基本数据类型,那么使用浅拷贝就足够了。但是,如果我们需要复制的对象包含嵌套的对象,那么就需要使用深拷贝。因为浅拷贝只是复制了引用,而深拷贝则会递归地复制整个对象树。

除了copy()和deepcopy()方法外,Python还提供了其他一些复制对象的方法,如slice操作符、list()构造函数等。这些方法也可以用于复制对象,但是它们都只能进行浅拷贝,不能进行深拷贝。

【二】深浅拷贝问题详解

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

(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还提供了一些其他的对象复制方法。下面介绍其中的几种方法。

slice操作符
slice操作符可以用于复制列表、元组、字符串等序列类型的对象。例如:

a = [1, 2, 3, 4]
b = a[:]
这里,b就是a的一个浅拷贝,它包含了a中所有元素的副本。由于slice操作符只进行浅拷贝,因此如果a中包含了嵌套的对象,那么b中的这些对象仍然是a中的引用。

2. list()构造函数

list()构造函数可以用于将其他序列类型的对象转换为列表,并且可以实现浅拷贝。例如:

a = (1, 2, 3, 4)
b = list(a)
这里,b就是a的一个浅拷贝,它包含了a中所有元素的副本。

另外,需要注意的是,Python中的一些内置类型,如int、str、tuple等是不可变类型,它们没有提供修改自身内容的方法。因此,对这些类型进行浅拷贝和深拷贝是没有任何区别的。例如:

a = 123
b = copy.copy(a)
c = copy.deepcopy(a)
这里,b和c都是a的副本,它们的值都是123。

最后,需要注意的是,在Python中,对象的复制和对象的赋值是不同的概念。对象的赋值只是将一个变量名与一个对象关联起来,而不是复制对象本身。例如:

a = [1, 2, 3]
b = a
这里,b只是a的一个别名,它们实际上指向同一个对象。因此,对a或b进行修改,都会影响到另一个变量。如果需要复制a的副本,可以使用a.copy()或者copy模块中的函数。

标签:python,list,列表,对象,深浅,ori,拷贝,copy
From: https://www.cnblogs.com/queryH/p/17880356.html

相关文章

  • # yyds干货盘点 # 分享一个Python网络爬虫数据采集利器
    前言你是否曾为获取重要数据而感到困扰?是否因为数据封锁而无法获取所需信息?是否因为数据格式混乱而头疼?现在,所有这些问题都可以迎刃而解。让我为大家介绍一款强大的数据收集平台——亮数据BrightData。作为世界领先的数据收集平台,亮数据以其高效、可靠和灵活的方式检索提取关键的......
  • [Python急救站]火车购票程序
    火车购票程序如果要一直执行程序,加个while循环即可。要是要智能判断月份,可以通过调取当前时间进行判断即可。print("""1、每年的1-3月和7-9月凭学生证可以打5折。2、10人(含10人)以上团购还可以打9折。""")i=eval(input("请输入单张火车票的全价:(1~1000):"))a=input("是否为......
  • 深浅拷贝
    深浅拷贝1.浅拷贝浅拷贝是指创建一个新对象,并将原始对象的元素复制到新对象中#num_list=[1,2,[3,4]]##使用浅拷贝创建拷贝对象#copy_list=copy.copy(num_list)###修改原对象中的可变数据类型#num_list[2].append(5)##print("原对象:",num_list) #[1,......
  • 深浅拷贝问题
    深浅拷贝问题copy.copy浅拷贝copy.deepcopy深拷贝浅拷贝copy.copycopy.copy浅拷贝原来的拷贝对象------拷贝出了一个新的对象修改原对象------原对象必须改变-----新对象也会随着原对象的改变而改变。总结:复制一份原来的对象,如果原来的对象中存在可变数据类型,那么修......
  • python
    conda虚拟环境使用conda创建虚拟环境后,正常情况激活并进入环境后,执行condainstall会安装到自己的环境,并且执行pipinstall也会安装到envs/环境名/lib/python3.8/site-packages目录下。但是我用服务器的时候,发现pipinstall竟然安装到别人的conda虚拟环境中了,经过漫长的搜索,解决......
  • Python - pandas DataFrame数据的合并与拼接(merge、join、concat)
    Python-pandasDataFrame数据的合并与拼接(merge、join、concat)0概述pandas包的merge、join、concat方法可以完成数据的合并和拼接。merge方法主要基于两个dataframe的共同列进行合并;join方法主要基于两个dataframe的索引进行合并;concat方法是对series或dataframe进行行......
  • Python中级之字符编码
    ASKII码GBK/SHIFT-JISUNICODE字符编码【一】什么是字符编码人类在与计算机交互时,用的都是人类能读懂的字符,如中文字符、英文字符、日文字符等而计算机只能识别二进制数二进制数即由0和1组成的数字,例如010010101010计算机是基于电工作的,电的特性即高低电平人类从逻......
  • Python中级之可变数据类型和不可变数据类型
    【一】可变数据类型对于可变类型(如字典、列表、集合),在函数中修改参数会影响原始对象。当你对于可变类型进行修改操作,并不会返回内容,而是将原本的内容进行了更新#字典(dict)dict1={'a':1,'b':2}dict1.update({'c':2})print(dict1)#{'a':1,'b':2,'c':2}#......
  • 【转】How to type pythonic codes
    谈到规范首先想到就是Python有名的PEP8代码规范文档,它定义了编写Pythonic代码的最佳实践。可以在 python.org/dev/peps/pep 上查看。但是真正去仔细研究学习这些规范的朋友并不是很多,对此呢这篇文章摘选一些比较常用的代码整洁和规范的技巧和方法,下面让我们一起来学习吧!......
  • 软件测试/人工智能|Python逻辑运算符如何灵活使用
    前言当初学者探索Python编程时,理解逻辑运算符是掌握编程逻辑和决策流程的重要一环。逻辑运算符允许我们对多个条件进行组合,以便进行更复杂的逻辑判断。让我们深入了解Python中常用的逻辑运算符及其使用方法。逻辑运算符逻辑运算符一般用来解决当有多个关系条件需要判断时使用,......