Python 提高篇学习笔记(一):深拷贝和浅拷贝

文章目录

  • 一、什么是对象的引用
  • 二、深拷贝和浅拷贝
    • 2.1 浅拷贝(Shallow Copy)
    • 2.2 深拷贝(Deep Copy)
    • 2.3 copy.copy和copy.deepcopy的区别

一、什么是对象的引用

在 Python 中,对象的引用是指变量指向内存中某个对象的地址或标识符。当你创建一个新的对象(比如一个整数、字符串、列表等),Python 会分配一块内存来存储这个对象,并且给这个对象分配一个唯一的标识符(也就是对象的地址)。当你将这个对象赋值给一个变量时,实际上这个变量就存储了对该对象的引用,而不是对象本身。这意味着变量并不直接包含对象的值,而是指向存储这个值的内存地址。

举例:

In [19]: x = [1, 2, 3] # 创建一个列表对象,并将其引用赋给变量x
In [20]: y = x # y和x现在指向同一个列表对象
In [21]: # 修改x所指向的列表对象
In [22]: x.append(4)
In [23]: print(y) # 输出[1, 2, 3, 4],因为y引用的是和x相同的列表对象
[1, 2, 3, 4]

在这个例子中,[1, 2, 3] 是一个列表对象,在内存中有自己的地址。x 这个变量包含了对这个列表对象的引用,而不是列表对象本身。如果你创建一个新的变量 y = x,那么 y 实际上也会指向同一个列表对象,即它们共享相同的引用。图示:
在这里插入图片描述
因此,对于可变对象(如列表、字典等), 如果多个变量引用了同一个对象,当你通过一个变量修改这个对象时,其他引用了相同对象的变量也会反映出这个修改。这是因为它们引用的是同一个对象,而不是对象的副本。对于不可变对象(如整数、字符串等), 由于对象本身是不可变的,任何修改都会导致新对象的创建,而不会影响原始对象,因为对不可变对象的修改实际上是创建了一个新对象并将变量重新指向新对象的地址。举例:

In [33]: x = 300
In [34]: y = x
In [35]: y = 400
In [36]: print(x, y)
300 400

图示:
在这里插入图片描述
补充:在 Python 中,== 和 is 是用于比较对象的运算符,但它们的作用不同:

== 操作符用于比较两个对象的值是否相等。
is 操作符用于检查两个对象是否是同一个对象,也就是比较它们的身份标识(即内存地址/引用)是否相同。示例如下:

In [39]: a = [1, 2, 3]
In [40]: b = [1, 2, 3]
In [41]: # 比较值是否相等
In [42]: print(a == b) # 输出True,因为列表a和列表b中的元素都相同
True
In [43]: # 检查是否是同一个对象
In [44]: print(a is b) # 输出False,因为a和b是不同的对象,即在内存地址/引用不一样
False

注意: 在 Python 中,有一个特定的机制用于缓存一定范围内的小整数对象,这个范围通常是 -5~256 (这个范围可能会因 Python 版本和具体实现而略有不同)。 这意味着在这个范围内的整数对象在 Python 程序中的生命周期中会被缓存并重用,而不是每次都创建新的对象。这个缓存机制是为了提高性能和节省内存。因为这些小整数在许多情况下是常用的,Python 会在启动时预先创建这些对象并将其缓存起来,当你需要使用这些整数时,Python 会直接返回缓存中的对象而不是创建新的对象。这种缓存机制使得在相同范围内的整数对象比较时,使用 is 操作符可能返回 True,因为它们指向相同的对象:

In [45]: x = 10
In [46]: y = 10
In [47]: print(x is y) # 输出True,因为x和y是同一个对象,由于小整数的缓存机制(有些也称为常量池)
True
In [48]: a = 300
In [49]: b = 300
In [50]: print(a is b) # 输出False,因为超出了小整数的缓存范围,a和b是不同的对象
False

二、深拷贝和浅拷贝

在 Python 中,深拷贝和浅拷贝是用于创建对象副本的概念。在理解这两者之间的区别之前,让我们先来看看它们的定义和用法。

2.1 浅拷贝(Shallow Copy)

浅拷贝创建一个新对象,但是只复制了对象的引用。这意味着原始对象及其副本引用了相同的子对象。当你对原始对象或副本对象做出改变时,子对象的改变会反映在两者之间。

在 Python 中,可以使用 copy 模块中的 copy() 方法来进行浅拷贝:

In [65]: import copy
In [66]: original_list = [1, 2, [3, 4]]
In [67]: new_list = original_list  # 赋值是最简单的浅拷贝
In [68]: id(original_list) # 用来显示original_list指向的数据的内存地址
Out[68]: 1837971633856
In [69]: id(new_list) # 用来显示new_list指向的数据的内存地址
Out[69]: 1837971633856In [70]: shallow_copied_list = copy.copy(original_list)
In [71]: # 修改shallow_copied_list副本中的元素
In [72]: shallow_copied_list[0] = 5
In [73]: # 修改子对象(原始对象和副本对象共享的对象)
In [74]: shallow_copied_list[2][0] = 6
In [77]: print(original_list, new_list)
[1, 2, [6, 4]] [1, 2, [6, 4]]
In [78]: print(shallow_copied_list)
[5, 2, [6, 4]]

图示:
在这里插入图片描述
字典示例:

In [131]: import copy
In [132]: d = dict(name='AmoXiang',age=19,hobby_list=['dance', 'sing'])
In [133]: co = copy.copy(d)
In [134]: d
Out[134]: {'name': 'AmoXiang', 'age': 19, 'hobby_list': ['dance', 'sing']}
In [135]: co
Out[135]: {'name': 'AmoXiang', 'age': 19, 'hobby_list': ['dance', 'sing']}
In [136]: id(d),id(co)
Out[136]: (1838005229056, 1838001691136)
In [137]: d['name'] = 'Amo'
In [138]: d
Out[138]: {'name': 'Amo', 'age': 19, 'hobby_list': ['dance', 'sing']}
In [139]: co
Out[139]: {'name': 'AmoXiang', 'age': 19, 'hobby_list': ['dance', 'sing']}
In [140]: co['hobby_list'].append('swim')
In [141]: co
Out[141]: {'name': 'AmoXiang', 'age': 19, 'hobby_list': ['dance', 'sing', 'swim']}
In [142]: d
Out[142]: {'name': 'Amo', 'age': 19, 'hobby_list': ['dance', 'sing', 'swim']}
In [143]: id(d['name']),id(co['name'])
Out[143]: (1837976233200, 1837949658800)
In [144]: id(d['age']),id(co['age'])
Out[144]: (1837896002416, 1837896002416)
In [145]: id(d['hobby_list']),id(co['hobby_list'])
Out[145]: (1837979180480, 1837979180480)
In [146]: co['age'] = 20
In [147]: co
Out[147]: {'name': 'AmoXiang', 'age': 20, 'hobby_list': ['dance', 'sing', 'swim']}
In [148]: d
Out[148]: {'name': 'Amo', 'age': 19, 'hobby_list': ['dance', 'sing', 'swim']}

浅拷贝对不可变类型和可变类型的 copy 不同:
copy.copy 对于可变类型,会进行浅拷贝
copy.copy 对于不可变类型,不会拷贝,仅仅是指向

In [159]: import copy
In [160]: a = [1,2,3]
In [161]: b = copy.copy(a)
In [162]: id(a),id(b)
Out[162]: (1838001649984, 1837979060672)
In [163]: a.append(4)
In [164]: a
Out[164]: [1, 2, 3, 4]
In [165]: b
Out[165]: [1, 2, 3]
In [166]: a = (1,2,3)
In [167]: b = copy.copy(a)
In [168]: id(a),id(b)
Out[168]: (1838005603584, 1838005603584)

2.2 深拷贝(Deep Copy)

深拷贝创建一个全新的对象,同时递归地复制了所有子对象。这意味着原始对象及其副本不共享任何子对象。无论你对原始对象还是副本对象做出任何改变,都不会影响对方。同样使用 copy 模块中的 deepcopy() 方法进行深拷贝:

In [90]: import copy
In [91]: original_list = [1, 2, [3, 4]]
In [92]: deep_copied_list = copy.deepcopy(original_list)
In [93]: id(original_list)
Out[93]: 1838005694912
In [94]: id(deep_copied_list)
Out[94]: 1838005773312
In [95]: # 修改副本的元素
In [96]: deep_copied_list[0] = 5
In [97]: # 修改子对象(原始对象和副本对象共享的对象)
In [98]: deep_copied_list[2][0] = 6
In [99]: print(original_list)  # 输出:[1, 2, [3, 4]]
[1, 2, [3, 4]]
In [100]: print(deep_copied_list)  # 输出:[5, 2, [6, 4]]
[5, 2, [6, 4]]
In [101]: print(id(original_list[2]))
1838004780096
In [102]: print(id(deep_copied_list[2]))
1838001793984

图示:
在这里插入图片描述

2.3 copy.copy和copy.deepcopy的区别

copy.copy 图示:
在这里插入图片描述
copy.deepcopy 有兴趣的可以自己画一下,这里我就不再进行赘述(图太难画了,偷下懒)。

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

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

相关文章

Unsupervised MVS论文笔记

Unsupervised MVS论文笔记 摘要1 引言2 相关工作3 实现方法 Tejas Khot and Shubham Agrawal and Shubham Tulsiani and Christoph Mertz and Simon Lucey and Martial Hebert. Tejas Khot and Shubham Agrawal and Shubham Tulsiani and Christoph Mertz and Simon Lucey and …

如何使用技术SEO来优化评论

你在网上购买吗?我的意思是,在当今时代,谁不这样做?作为买家,无论您想购买什么,您都了解全面和高质量评论的价值。这是您在决定是否购买产品时考虑的重要因素。 这就是为什么许多人在网上购物之前使用评论…

Python中用requests时遇到的错误警告解决方案

最近,我在Python 2.7.6(Ubuntu 14.04.2 LTS)环境中将requests库的版本从2.5.3升级到2.6.0,却遇到了’A true SSLContext object is not available’警告。每当我在Python 2.7.6环境中尝试使用requests库访问’github’时&#xff…

实时错误’-2147217887‘多步OLB DB 操作产生错误。如果可能,请检查OLE DB状态值

目录 背景问题问题分析问题解决 错误解决与定位技巧总结 背景 仍旧是学生信息管理系统的问题,当时做的时候没发现这么多问题呢,只能说明一件事,做的时候没有站在用户的角度考虑需求,设置了什么内容,就按照设置好的去测…

20k阿里面经跟18k腾讯面经(附答案)

阿里面经 1、你的测试职业发展是什么? 测试经验越多,测试能力越高。所以我的职业发展是需要时间积累的,一步步向着高级测试工程师奔去。而且我也有初步的职业规划,前3年积累测试经验,按如何做好测试工程师的要点去要求…

三、防火墙-源NAT

学习防火墙之前,对路由交换应要有一定的认识 源NAT基本原理1.1.NAT No-PAT1.2.NAPT1.3.出接口地址方式(Easy IP)1.4.Smart NAT1.5.三元组 NAT1.6.多出口场景下的源NAT 总结延伸 ——————————————————————————————…

个人博客项目 - 测试报告

文章目录 一、项目背景二、测试报告功能测试1.编写测试用例2.登录测试3.编写文章测试4.查看文章测试5.删除文章测试7.注销登录测试 自动化测试性能测试1.VUG2.进行场景设计3.生成性能测试报告 总结 本文开始 一、项目背景 通过学习测试相关的知识,动手实践并测试一…

2023 年 亚太赛 APMCM ABC题 国际大学生数学建模挑战赛 |数学建模完整代码+建模过程全解全析

当大家面临着复杂的数学建模问题时,你是否曾经感到茫然无措?作为2022年美国大学生数学建模比赛的O奖得主,我为大家提供了一套优秀的解题思路,让你轻松应对各种难题。 以五一杯 A题为例子,以下是咱们做的一些想法呀&am…

【DevOps】Git 图文详解(八):后悔药 - 撤销变更

Git 图文详解(八):后悔药 - 撤销变更 1.后悔指令 🔥2.回退版本 reset3.撤销提交 revert4.checkout / reset / revert 总结 发现写错了要回退怎么办?看看下面几种后悔指令吧! ❓ 还没提交的怎么撤销&#x…

二十二、数组(4)

本章概要 随机生成泛型和基本数组 随机生成 我们可以按照 Count.java 的结构创建一个生成随机值的工具: Rand.java import java.util.*; import java.util.function.*;import static com.example.test.ConvertTo.primitive;public interface Rand {int MOD 10_0…

兼顾陪读|自由职业者赴美国加州大学尔湾分校访学

I老师出国访学除了提升自己的科研水平外,主要目标还是以陪伴孩子上学为主。最终我们为其落实了排名还不错的加州大学尔湾分校的职位,这对于已多年脱离科研工作岗位,学术背景非常薄弱的I老师来说相当不易。 I老师背景: 申请类型&a…

22LLMSecEval数据集及其在评估大模型代码安全中的应用:GPT3和Codex根据LLMSecEval的提示生成代码和代码补全,CodeQL进行安全评估

LLMSecEval: A Dataset of Natural Language Prompts for Security Evaluations 写在最前面主要工作 课堂讨论大模型和密码方向(没做,只是一个idea) 相关研究提示集目标NL提示的建立NL提示的建立流程 数据集数据集分析 存在的问题 写在最前面…