Python 编程 深入了解内存管理机制、深拷贝与浅拷贝

🍉 CSDN 叶庭云https://yetingyun.blog.csdn.net/


一、对象和引用、内存管理机制

在这里插入图片描述

Python 中的一切都是对象,包括数字、字符串、列表和函数等。为了简化内存管理并提高效率,Python 采用了统一的对象模型。在这个模型中,所有创建的变量在栈上都是指向堆中实际分配内存对象的引用。这种机制允许变量指向不同类型的对象,并可以在程序运行期间随时改变所指向的对象。这种设计使得 Python 的内存使用更加高效和灵活。对象还分两类:一类是可变的,一类是不可变的。

  • 不可变对象类型有:整数、浮点数、布尔值、字符串、元组等

  • 可变对象类型有:列表、字典、集合、可变的字节数组、用户自定义类

Python 的内存管理机制,包括引用计数、垃圾回收和内存池机制,是以对象引用为基础的。通过妥善管理对象引用,Python 能够高效地管理内存使用并回收不再使用的对象。

  • 内存池机制和垃圾回收是 Python 内存管理机制的两个主要组成部分,其目标是减少内存碎片化和提高程序执行效率。内存池通过预先申请内存块来避免频繁调用 new/malloc 所带来的性能损耗。

  • 垃圾回收则主要依赖引用计数机制,辅以标记-清除算法和分代回收策略,以解决循环引用问题并提高回收效率。引用计数记录每个对象被引用的次数,当引用计数降为零时,该对象将被视为垃圾并进行回收。标记-清除算法用于处理循环引用问题,而分代回收则通过将对象分为不同的代来提高回收效率。这些机制共同确保 Python 程序的高效执行,同时减轻了开发者在内存管理方面的负担。

is== 在比较对象时的内容是不同的。具体来说,is 比较的是两个对象的内存地址,以确定它们是否为同一个实例对象;而 == 则比较的是对象的值是否相等,这通常涉及到调用对象的 __eq__() 方法。

Python 中的整数缓存特性。对于小整数,范围在(-5 ~ 256)之间的整数,使用 ==is 运算符得到的结果是相同的。这是因为 Python 在内部建立了一个数组缓存,当创建小整数对象时,会直接引用缓存中已有的对象,而不是每次都创建新的对象。在 Python 脚本中运行代码时,编译器可以看到整个程序并进行优化,所以超出范围的整数也会直接引用缓存中已有的对象。不同的 Python 版本和代码运行环境可能会影响整数缓存的功能哦!


二、深拷贝与浅拷贝

深拷贝和浅拷贝是 Python 中两种重要的对象复制方法

浅拷贝是通过复制对象的引用而非对象本身来实现的。在顶层,原始对象和复制的对象是独立的对象(内存地址不同,可用 id() 函数查看),但里面的子对象都是引用。在 Python 中,我们可以利用 copy 模块的 copy() 函数来创建一个对象的浅拷贝。对于基本数据类型(整数、浮点数、布尔值、字符串)或只包含不可变对象的复合数据类型(列表、元组、字典、集合),浅拷贝是安全且高效的。但如果原始对象包含其他可变对象有嵌套的复杂对象,例如:列表中的列表和字典中的字典),则复制的对象将与原始对象共享内部子对象。这意味着对复制对象的内部子对象的修改也会反映在原始对象上。这就是为什么当原始对象包含其他可变子对象时,浅拷贝可能会带来问题

这里注意一点:直接赋值其实就是对象的引用(别名),都指向同一个对象。因此,直接赋值跟浅拷贝 copy.copy() 还是有一定区别的。

深拷贝用于确保原始对象与复制对象之间的完全独立。它递归地复制原始对象及其所有子对象,从而创建一个与原始对象完全独立的新对象。这意味着对深拷贝对象的修改完全不会影响原始对象。Python 的 copy 模块提供了 deepcopy() 函数,用于执行深拷贝。deepcopy() 的工作原理如下

  1. 检查对象的类型:首先,deepcopy() 会检查对象的类型。对于不同的类型,复制过程可能有所不同。

  2. 递归复制:对于嵌套的对象(如列表中的列表、字典中的字典和自定义对象等),deepcopy() 会复制原始对象及其所有子对象。这意味着它会继续对每个子对象执行深拷贝,直到遇到基本数据类型(如整数、字符串、浮点数等)为止。

  3. 处理循环引用:在复制过程中,deepcopy() 需要处理循环引用的情况。如果对象之间存在循环引用,deepcopy() 会跟踪这些引用,并确保在复制过程中不会创建无限递归的复制。

  4. 返回新对象:完成所有的复制后,deepcopy() 返回一个新的、与原始对象完全独立的复制对象。

浅拷贝适用于对象结构较为简单或仅需复制对象顶层结构的情况。而深拷贝则适用于对象结构复杂且需要完全独立副本的场景。在选择使用深拷贝还是浅拷贝时,应综合考虑对象的结构和复制需求。

虽然深拷贝提供了对象的完全独立性,但对于特别大的对象或包含复杂引用的对象,它比浅拷贝更耗时和消耗内存,因为它需要递归地复制原始对象及其所有子对象。此外,在某些情况下,如包含互相引用的对象,深拷贝可能会引起无限递归地尝试复制,直到达到 Python 的最大递归深度限制,从而引发 RecursionError。因此,在决定是否使用深拷贝时,需要根据实际需求权衡其优点和缺点。

总结:Python 中的深拷贝和浅拷贝对于有效地管理对象的复制至关重要。浅拷贝在对象结构较为简单、资源消耗较少的情况下提供了高效的复制方法,而深拷贝则适用于需要完全独立对象副本的复杂对象结构。在实际应用中,选择正确的拷贝方法可以避免潜在的程序错误并提高代码的效率。


📚️ 相关链接:

  • 面试必备:Python 内存管理机制

  • Python 中的深拷贝和浅拷贝有什么区别

  • Python 直接赋值、浅拷贝和深度拷贝解析

  • Python 深拷贝和浅拷贝详解

  • 彻底理解 Python 中浅拷贝和深拷贝的区别

  • Python 的 “is None” vs “==None”

  • [python] 魔术方法大全(二)-- 比较篇

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

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

相关文章

【考研数学】看张宇的书,高效自学攻略

张宇老师的课程,我建议还是认真听一下 因为张宇老师视频课并不是照本宣科的读讲义,他是真的有自己的教学方法 讲义上的概念,老师自己会在A4纸上带大家过一遍,并且遇到关键的知识点,老师会强调 张宇老师还会帮我们记…

[C语言][数据结构][链表] 双链表的从零实现!

目录 零.必备知识 0.1 一级指针 && 二级指针 0.2 双链表节点的成员列表 a. 数据 b. 后驱指针 c. 前驱指针 0.3 动态内存空间的开辟 一. 双链表的实现与销毁 1.1 节点的定义 1.2 双向链表的初始化 && 创建新节点 1.3 尾插 1.4 头插 1.5 尾删 1.6 头删 1…

MySQL8.0.36-社区版:错误日志(2)

mysql有个错误日志,是专门记录错误信息的,这个功能默认是开启的 一般都是在/var/log/mysqld.log 日志中存放 1.错误日志的位置 首先我们使用命令去查看一下,这个错误日志文件究竟在哪 进入到mysql中,使用命令 show variables…

二叉树遍历(前序创建|中序遍历)

牛客题目链接 目录 1.解题思路 1.1中序遍历打印 ​1.2前序创建二叉树 1.3注意点 博主这里用的是java实现 随手记一个知识: hasNext读取到空格或者换行符会结束 hasNextLine读取到换行符才会结束(空格不会退出) 为什么要强调这个呢? …

Vivado Design Suite中的增量实现和增量模式

Vivado Incremental(增量)是Xilinx FPGA设计工具中的一种功能,它允许对设计的一部分进行修改和重新编译,而不需要对整个设计进行重新编译。这种增量式的方法可以显著减少编译时间,特别是在进行小的修改或迭代开发时。 …

std::stringstream

std::stringstream 是 C 标准库中的一个类,用于对字符串进行输入输出操作,类似于文件流(std::ifstream 和 std::ofstream)。它允许你像使用 std::cin 和 std::cout 一样使用字符串。 std::stringstream 可以将字符串作为输入源&am…

ThreadPoolExecutor线程池解析

ThreadPoolExecutor线程池解析 一、ThreadPoolExecutor常见参数 jdk中Executors提供了几种常用的线程池,底层都是ThreadPoolExecutor。 public ThreadPoolExecutor(int corePoolSize,//核心线程数int maximumPoolSize,// 最大线程数long keepAliveTime,//非核心线程…

大数据产品有哪些分类?各类里知名大数据产品都有哪些?

随着互联网技术的持续进步和全球数字化转型的推进,我们正处于一个数据爆炸的时代。在这样的大背景下,大数据已经逐渐崭露头角,成为了推动各行各业发展的关键因素和核心资源。大数据不仅仅是指数据的规模巨大,更重要的是它蕴含的价…

量子信息产业生态研究(一):关于《量子技术公司营销指南(2023)》的讨论

写在前面。量子行业媒体量子内参(Quantum Insider)编制的《量子技术公司营销指南》是一本实用的英文手册,它旨在帮助量子科技公司建立有效的营销策略,同时了解如何将自己定位成各自的行业专家。本文对这篇指南的主要内容进行了翻译…

ubuntu上安装截图工具-Flameshot及其使用步骤说明

Flameshot 火焰截图-推荐 安装命令: sudo apt install flameshot 操作方式: 1)打开 2)右上角弹窗 3)点击后弹出 选择进行截图 4)截图后再选择分享 5)再重新选择区域,出现编辑…

【蓝桥杯】2024年第15届真题题目

试题 A: 握手问题 本题总分: 5 分 【问题描述】 小蓝组织了一场算法交流会议,总共有 50 人参加了本次会议。在会议上, 大家进行了握手交流。按照惯例他们每个人都要与除自己以外的其他所有人进 行一次握手(且仅有一次&a…

CMD 汉字乱码处理

windows 11 cmd汉字乱码问题处理 一 查看CMD编码 win R 输入 cmd 输入 chcp 查看回显信息 “936”代表的意思就是 GBK (汉字内码扩展规范),通常情况下GBK也是cmd的默认编码。 解决乱码需要把编码改为 utf-8 二 临时修改 在 终端中输入 chcp 65001 三 永久修改…

蓝桥杯嵌入式第十五届省赛真题题目

蓝桥杯昨天也考完了,大家可以看看题目 客观题题目 程序题题目

【Python函数和类4/6】递归与匿名函数

目录 目标 匿名函数 多个形参 匿名函数的局限性 递归 语言例子 数学例子 递归的实现 递归代码 练习 总结 目标 在之前的博客中,我们学习了定义函数、调用函数以及设置函数的参数。在今天,我们会补充函数的两个常见的知识点,一个是匿…

学浪视频怎么缓存?

缓存学浪视频轻而易举!推荐使用“小浪助手”,一款便捷的工具,助你轻松实现。工具已经预先打包好,需要的朋友可以自行下载。快试试,畅享学习吧! 学浪下载器链接:https://pan.baidu.com/s/1y7vcq…

spring容器

spring容器 实现方式 spring中提供了各式各样的IOC容器的实现供用户选择和使用,使用什么样的容器取决于用户的需要 BeanFactory 该接口是最简单的容器,提供了基本的DI支持。最常用的BeanFactory实现是XmlBeanFactory类,根据XML文件中的定义加…

RetinalNet论文笔记

RetinalNet 概述1. 引言2. 相关工作3. 焦点损失4. RetinaNet Detector 检测器5. 实验6. 结论 3. Focal loss3.1. 平衡交叉熵3.2. 焦点损失定义3.3. 类别不平衡和模型初始化3.4. 类别不平衡和两阶段检测器 4. RetinaNet Detector特征金字塔网络骨干(Feature Pyramid …

PostgreSQL入门到实战-第二十五弹

PostgreSQL入门到实战 PostgreSQL中表连接操作(九)官网地址PostgreSQL概述PostgreSQL中NATURAL JOIN命令理论PostgreSQL中NATURAL JOIN命令实战更新计划 PostgreSQL中表连接操作(九) 使用PostgreSQL NATURAL JOIN从两个表中查询数据。 官网地址 声明: 由于操作系统, 版本更新…

C++实现AVL树

文章目录 一、平衡树的优势二、二叉平衡搜索树的节点定义三、二叉搜索树的插入3.1 寻找插入位置3.2 开始判定平衡因子,平衡因子有变就开始旋转3.2.1 左旋的情况3.2.2 左旋代码(一定要考虑平衡因子为2或者-2的节点是否有父节点)3.2.2 右旋的情…

DC-5渗透测试复现

DC-5渗透测试复现 目的: 获取最高权限以及5个flag 过程: 信息打点-文件包含漏洞-弹shell- scren-4.0.5提权 环境: 攻击机:kali(192.168.85.136) 靶机:DC_3(192.168.85.134) 复现: 一.信息收集 nma…