Python内存优化技巧

Python 优化内存管理 Python 作为一种动态类型编程语言,在 OOP 方面有更大的灵活性。 阅读详情
当您的项目规模越来越大时,高效管理内存资源就成为必然要求。遗憾的是,Python,尤其是与 C 或 C++ 等低级语言相比,似乎内存效率不够高。现在是否应该更换编程语言?当然不是。事实上,从优秀的模块和工具到先进的数据结构和算法,有很多方法可以显著优化 Python 程序的内存使用。
本文将重点介绍 Python 的内置机制,并介绍 7 种原始但有效的内存优化技巧。掌握这些技巧将大大提高你的 Python 编程能力。

1.在类定义中使用"slots"

  • Python 作为一种动态类型编程语言,在 OOP 方面有更大的灵活性。在运行时向 Python 类中添加额外的属性和方法就是一个很好的例子。
  • 例如,下面的代码定义了一个名为 Author 的类。它最初有两个属性 name 和 age。但我们可以在稍后轻松地添加一个额外的属性:
class Author:
def __init__(self, name, age):
self.name = name
self.age = age
me = Author('Yang Zhou', 30)
me.job = 'Software Engineer'
print(me.job)
# Software Engineer

  • 然而,任何硬币都有两面。这种灵活性会浪费更多内存。
  • 因为 Python 中每个类的实例都会维护一个特殊的字典 (__dict__),用于存储实例变量。由于字典的底层是基于哈希表的实现,因此字典本身的内存效率很低,因此字典会消耗大量内存。
  • 在大多数情况下,我们不需要在运行时更改实例的变量或方法,而且在类定义之后,__dict__ 也不会被更改。因此,我们最好不要维护 __dict__ 字典。
  • Python 为此提供了一个神奇的属性:__slots__。
  • 它通过指定类的所有有效属性的名称,起到白名单的作用:
class Author:__slots__ = ('name', 'age')
def __init__(self, name, age):
self.name = name
self.age = age
me = Author('Yang Zhou', 30)
me.job = 'Software Engineer'
print(me.job)
# AttributeError: 'Author' object has no attribute 'job'

  • 就像上面的代码,我们不能再在运行时添加工作属性了。因为 __slots__ 白名单只定义了 name 和 age 两个有效属性。
  • 从理论上讲,由于属性是固定的,Python 不需要为它维护一个字典。它只需为 __slots__ 中定义的属性分配必要的内存空间即可。
  • 让我们写一个简单的比较程序来看看它是否真的可以这样工作:
import sys class Author:
def __init__(self, name, age):
self.name = name
self.age = age
class AuthorWithSlots:
__slots__ = ['name', 'age']
def __init__(self, name, age):
self.name = name
self.age = age

# Creating instances
me = Author('Yang', 30)
me_with_slots = AuthorWithSlots('Yang', 30)

# Comparing memory usage
memory_without_slots = sys.getsizeof(me) + sys.getsizeof(me.__dict__)
memory_with_slots = sys.getsizeof(me_with_slots)  # __slots__ classes don't have __dict__

print(memory_without_slots, memory_with_slots)
# 152 48
print(me.__dict__)
# {'name': 'Yang', 'age': 30}
print(me_with_slots.__dict__)
# AttributeError: 'AuthorWithSlots' object has no attribute '__dict__'

  • 如上面的代码所示,由于使用了 __slots__,实例 me_with_slots 没有__dict__ 字典。与需要保存额外字典的 me 实例相比,它有效地节省了内存资源。

2.使用生成器

  • 生成器是 Python 中列表的懒版本。它们的工作方式类似于元素生成工厂:每当调用 next() 方法时就生成一个项,而不是一次性计算所有项。因此,在处理大型数据集时,它们非常节省内存。
def number_generator():
for i in range(100):yield i
numbers = number_generator()
print(numbers)
# <generator object number_generator at 0x104a57e40>
print(next(numbers))
# 0
print(next(numbers))
# 1

  • 上面的代码展示了一个编写和使用生成器的基本示例。关键字 yield 是生成器定义的核心。使用它意味着只有在调用 next() 方法时,才会产生项目 i。
  • 现在,让我们比较一下生成器和列表,看看哪一个更节省内存:
import sys numbers = []
for i in range(100):numbers.append(i)
def number_generator():
for i in range(100):yield i
numbers_generator = number_generator()
print(sys.getsizeof(numbers_generator))
# 112
print(sys.getsizeof(numbers))
# 920

  • 上述程序的结果证明,使用生成器可以大大节省内存使用量。
  • 顺便提一下,如果我们把 list 理解的方括号转换成小括号,它就会变成一个生成器表达式。这是在 Python 中定义生成器的一种更简单的方法:
import sys
numbers = [i for i in range(100)]
numbers_generator = (i for i in range(100))
print(sys.getsizeof(numbers_generator))
# 112
print(sys.getsizeof(numbers))
# 920


3.利用内存映射文件支持大文件处理

  • 内存映射文件 I/O,简称 mmap,是一种操作系统级优化。

维基百科:它实现了需求分页,因为文件内容不会立即从磁盘读取,最初根本不使用物理 RAM。从磁盘实际读取的操作是在访问特定位置后,以一种懒惰的方式进行的。

  • 简单地说,当使用 mmap 技术对文件进行内存映射时,它会直接在当前进程的虚拟内存空间中创建文件的映射,而不是将整个文件加载到内存中。映射而不是加载整个文件可以节省大量内存。
  • 看起来很复杂?幸运的是,Python 已经提供了使用这种技术的内置模块,因此我们可以轻松利用它,而无需考虑操作系统级的实现。
  • 例如,在 Python 中如何使用 mmap 进行文件处理:
import mmap
with open('test.txt', "r+b") as f:# memory-map the file, size 0 means whole file
with mmap.mmap(f.fileno(), 0) as mm:# read content via standard file methods
print(mm.read())# read content via slice notation
snippet = mm[0:10]
print(snippet.decode('utf-8'))

  • 如上所述,Python 使内存映射文件 I/O 技术的使用变得非常方便。我们需要做的仅仅是应用 mmap.mmap() 方法,然后使用标准文件方法甚至切片符号来处理打开的对象。

4.尽量少用全局变量

  • 全局变量具有全局作用域,因此只要程序运行,全局变量就会一直保留在内存中。
  • 因此,如果一个全局变量包含一个大型数据结构,它就会在整个程序生命周期中占用内存,从而可能导致内存使用效率低下。
  • 我们应该在 Python 代码中尽量减少全局变量的使用。

5.利用逻辑操作符

  • 这个技巧看似微妙,但巧妙地使用它将极大地节省程序的内存使用量。
  • 例如,下面是一个简单的代码片段,它根据两个函数返回的布尔值得到最终结果:
result_a = expensive_function_a()
result_b = expensive_function_b()
result = result_a if result_a else result_b

  • 上述代码可以正常运行,但它实际上执行了两个内存不足的函数。
  • 获得相同结果的更聪明的方法如下:
result = expensive_function1() or expensive_function2()

  • 由于逻辑运算符遵循短路评估规则,如果 expensive_function1() 为 True,则不会执行上述代码中的 expensive_function2()。这将节省不必要的内存使用。

6.谨慎选择数据类型

  • 资深的 Python 开发人员会谨慎而精确地选择数据类型。因为在某些情况下,使用一种数据类型比使用另一种数据类型更节省内存。
元组比列表更节省内存
  • 鉴于元组是不可变的(创建后不能更改),它允许 Python 在内存分配方面进行优化。然而,列表是可变的,因此需要额外的空间来容纳潜在的修改。
import sys
my_tuple = (1, 2, 3, 4, 5)
my_list = [1, 2, 3, 4, 5]
print(sys.getsizeof(my_tuple))
# 80
print(sys.getsizeof(my_list)) 
# 120

  • 如上面的代码段所示,即使包含相同的元素,元组 my_tuple 使用的内存也比 list 少。
  • 因此,如果在创建后不需要更改数据,我们应该首选元组而不是列表。
数组比 list 更节省内存
  • Python 中的数组要求元素具有相同的数据类型(例如,所有整数或所有浮点数),但列表可以存储不同类型的对象,这就不可避免地需要更多内存。
  • 因此,如果列表的元素都是同一类型,使用数组会更节省内存:
import sys
import array
my_list = [i for i in range(1000)]
my_array = array.array('i', [i for i in range(1000)])
print(sys.getsizeof(my_list))  
# 8856
print(sys.getsizeof(my_array)) 
# 4064

优秀的数据科学模块比内置数据类型更高效
  • Python 是数据科学的统治语言。有许多强大的第三方模块和工具提供了更多的数据类型,如 NumPy 和 Pandas。
  • 如果我们只需要一个简单的一维数组,而不需要 NumPy 提供的广泛功能,那么 Python 的内置数组可能是一个不错的选择。
  • 但如果需要进行复杂的矩阵操作,使用 NumPy 提供的数组可能是所有数据科学家的首选,也可能是最佳选择。

7.对相同字符串应用字符串互文技术

  • 下面的代码会让很多开发人员感到困惑:
>>> a = 'Y'*4096
>>> b = 'Y'*4096
>>> a is b
True
>>> c = 'Y'*4097
>>> d = 'Y'*4097
>>> c is d
False

  • 我们知道,is 运算符用于检查两个变量是否指向内存中的同一个对象。它与 == 运算符不同,后者用于比较两个对象是否具有相同的值。
  • 那么,为什么 a is b 得到的是 True,而 c is d 得到的却是 False 呢?
  • 如果有几个小字符串的值相同,Python 就会隐式地对它们进行内联,并引用内存中的同一个对象。
  • 定义小字符串的神奇数字是 4096。因为 c 和 d 的长度都是 4097,所以它们在内存中是两个对象,而不是一个。不再有隐式字符串互调。因此,当执行 c 是 d 时,我们会得到一个 False。
  • 字符串互调是一种优化内存使用的强大技术。如果我们想显式地进行字符串互调,sys.intern() 方法就很好用:
>>> import sys
>>> c = sys.intern('Y'*4097)
>>> d = sys.intern('Y'*4097)
>>> c is d
True

  • 顺便说一下,除了字符串互调,Python 还将互调技巧应用于小整数。我们还可以利用它来优化内存。
    图片
总结
  • 最后希望你编程学习上不急不躁,按照计划有条不紊推进,把任何一件事做到极致,都是不容易的,加油,努力!相信自己!
文末福利
  • 最后这里免费分享给大家一份Python全套学习资料,希望能帮到那些不满现状,想提升自己却又没有方向的朋友,也可以和我一起来学习交流呀。
包含编程资料、学习路线图、源代码、软件安装包等!【[点击这里]】领取!
  • ① Python所有方向的学习路线图,清楚各个方向要学什么东西
  • ② 100多节Python课程视频,涵盖必备基础、爬虫和数据分析
  • ③ Python实战案例,学习不再是只会理论
  • ④ Python漫画教程,手机也能学习
可以扫描下方二维码领取【保证100%免费】

在这里插入图片描述

Python内存优化的实战技巧详解 Python是一种高级编程语言,以其易读性和强大的功能而广受欢迎。然而,由于其动态类型和自动内存管理,Python在处理大量数据或高性能计算时,内存使用效率可能不如一些低级语言。本文将介绍几种Python内存优化的技巧,并提供相应的示例代码,帮助在开发中更高效地管理内存。 阅读详情

相关推荐

内存不够用?Python优化内存利器

与列表、元组等容器类型不同的是,它们并不会把数据一次性读入内存,而是在需要使用时才生成数据。因此,当数据较大时,使用生成器和迭代器可以减少内存开销。在处理矩阵和表格等数据结构时,使用NumPy和Pandas能够优化内存使用。Python的垃圾回收机制会自动回收不再使用的内存。然而,有些大的对象可能需要更长时间才能被垃圾回收,从而占用了大量的内存。如何有效地优化Python内存?总之,Python中有许多优秀的工具可以帮助优化内存使用。比如,可以读取文件的部分数据进行处理,而不是一次性读取整个文件。

BUG?不存在的! 634

7个Python内存优化技巧,你用过几个?

当我们的项目变得越来越大时,高效管理计算资源是一个不可避免的要求。不幸的是,与低级语言如C或C++相比,Python在内存效率方面似乎不够。那么,现在应该更改编程语言吗?当然不是。事实上,有许多方法可以显著优化Python程序的内存使用,从优秀的模块和工具到先进的数据结构和算法。本文将聚焦于Python的内置机制,并介绍7个原始但有效的内存优化技巧。掌握这些技巧将显著提高我们的Python编程技能...

Warmer_Sweeter 2236

Python内存优化技巧:高效利用内存空间

优化Python代码的内存消耗是一个重要的任务,特别是在处理大数据集或需要处理大量数据时。内存映射文件允许将文件的内容映射到内存中,使你可以像访问内存一样访问文件的内容,而无需将整个文件加载到内存中。当处理大型数据集时,将数据分批处理可以显著减少内存消耗。相对于一次性加载整个数据集,将数据拆分为较小的块,逐个处理每个块,可以减少每个时间点在内存中所需的数据量。在处理大量数据时,及时释放不再需要的内存可以提高程序的内存利用率。是一个生成器表达式,它一次生成一个被处理过的行,而不是将所有行存储在内存中。

HackNebulaZ的博客 279

chatgpt赋能python:Python内存设置——如何优化你的Python代码性能

Python在处理程序数据时,需要将其存储在内存中。默认情况下,Python使用一种名为“垃圾回收”的机制来管理内存。垃圾回收会自动释放不再被使用的内存空间。但是,在处理大量数据或执行复杂任务时,Python可能会使用大量内存,导致性能问题。为了避免这种情况,Python允许我们手动设置内存限制。我们可以设置最大使用的内存量,以确保程序不会超出内存限制而崩溃。本文由chatgpt生成,文章没有在chatgpt生成的基础上进行任何的修改。以上只是chatgpt能力的冰山一角。作为通用的Aigc。

vacvefito的博客 827

QUIC 协议域名封堵:核心原理、关键技术与实现路径(C/C++代码实现)

随着 QUIC 协议在互联网领域的广泛应用,其基于 UDP 的传输特性与加密设计,打破了传统 TCP 协议下的域名封堵逻辑,给网络合规管理与安全防护带来新的技术难题。本文将脱离具体代码实现,聚焦 QUIC 协议域名封堵的核心原理、关键技术环节与实际落地路径,从协议特性本质出发,解析如何在遵循 RFC 9000、RFC 9001 等规范的前提下,实现对 QUIC 流量的精准域名封堵。

chen1415886044的博客 1466

SolidWorks参数化建模实战:从规则定义到智能装配

本文深入探讨SolidWorks参数化建模的实战技巧,从规则定义到智能装配的全流程。通过实际案例展示如何提升设计效率300%,确保一致性,并加速系列化开发。重点解析草图阶段植入设计意图、装配体级参数化及高级技巧,帮助工程师掌握三维建模的核心竞争力。

weixin_29306317的博客 416

Python 内存优化小技巧

_slots__Python 作为一种动态类型编程语言,在 OOP 方面有更大的灵活性。在运行时向 Python 类中添加额外的属性和方法就是一个很好的例子。例如,下面的代码定义了一个名为 Author 的类。它最初有两个属性 name 和 age。然而,任何硬币都有两面。这种灵活性会浪费更多内存。因为 Python 中每个类的实例都会维护一个特殊的字典 (__dict__),用于存储实例变量。由于字典的底层是基于哈希表的实现,因此字典本身的内存效率很低,因此字典会消耗大量内存。

2301_82275412的博客 956

LK32T102 单片机 操作GPIO实现流水灯(1)

前言: LK32T10232(32位)单片机是一款专为电机控制器和数字电源开发的高性能 MCU。采Cortex-M0 内核,最高工作频率可达 72Mhz,ADC 采样速率 达 1Msps。同时具备协处理器单元可满足各种乘法、除法、移位以及各种 复杂函数运算。 LK32T102(32位)支持单电源供电,且内嵌高精度高速及低速振荡器,以及具备 多种低功耗工作模式。同时,集成了多路增强型 PWM,多通道模拟比较 器和高速运算放大器,可满足多种电机及功率控制应用,并简化系统成本。...

qq_58676187的博客 3189

Python7种优化内存小技巧

重点介绍Python的内置机制,并介绍7种原始但有效的内存优化技巧。掌握这些技巧将大大提高你的Python编程能力。

m0_75067629的博客 1157

射频工程师笔记---射频通信基础

回顾一下移动通信技术的发展,其实是互联网和通信技术的融合过程。在这个过程中,很多应用都在不断加入其中。比如计算机跟通信的融合产生了互联网、互联网跟手机的融合带来了移动互联网。手机可以看杂志、看视频、听音乐,于是又出现了内容服务产业;再后来,电视音箱等设备也能联网,于是网络跟家电又产生了融合。所以应用的出现总是在融合其他产业。在1995年,比尔·盖茨在《未来之路》一书中首次提出:在未来...

多年硬件从业经历,热爱学习,记录生活! 2万+

SAP_SD模块更改销售订单定价简介

方式优点缺点适用场景MASS简单,无需开发不能触发重新定价逻辑修改特定字段BDC (VA02)可模拟人工操作维护复杂,速度慢少量订单批改稳定、安全需ABAP支持推荐用于批量重新定价VBOF标准重算返利仅适返利类条件返利更新通过本文,我们了解了 SAP 的[SAP_SD模块更改销售订单定价]的基本概念和应用方法。希望这些信息能帮助您在实际工作中更好地使用 SAP 系统,提高工作效率和管理水平。更多SAP文章请点击更多SAP文章更新,大家一起学习进步!!!

我小时候很黑的博客 713

Python 内存优化的高级技巧

Python 内存优化是一个复杂但重要的主题。通过使用生成器、局部变量、内置数据类型、`__slots__` 和内存池等技巧,我们可以有效地减少内存占用,提高程序的性能。希望本文介绍的这些技巧能对你在实际开发中的内存优化工作有所帮助。```

2501_91229761的博客 1361

复习单片机:动态数码管(1 数码管介绍+2 74HC245 和 74HC138 芯片介绍+3 硬件设计+4 软件设计+5 实验现象)

复习单片机:动态数码管(1 数码管介绍+2 74HC245 和 74HC138 芯片介绍+3 硬件设计+4 软件设计+5 实验现象)

wo12369874的博客 1701

6个Python内存条的优化小技巧

_slots__Python 作为一种动态类型编程语言,在 OOP 方面有更大的灵活性。在运行时向 Python 类中添加额外的属性和方法就是一个很好的例子。例如,下面的代码定义了一个名为 Author 的类。它最初有两个属性 name 和 age。然而,任何硬币都有两面。这种灵活性会浪费更多内存。因为 Python 中每个类的实例都会维护一个特殊的字典 (__dict__),用于存储实例变量。由于字典的底层是基于哈希表的实现,因此字典本身的内存效率很低,因此字典会消耗大量内存。

GLB_0627的博客 1102

国网DLT698.45协议——采集系统、数据交换(三)

物理层规定了通信单元或其他终端设备与多功能电表的通信接口,接口的物理与电气特性。常见的物理层传输方式有对于RS485、红外、载波通信等通信信道。将数据包装成可传输的帧格式。1、根据通信配置参数完成端口的初始化配置,通信状态初始化为准备接收状态,初始化相关计数器及缓冲区指针。2、链路层及控制子模块负责通信数据的收发控制,各类超时问题的处理。无通信数据接收时,定时初始化通信端口。3、完成协议帧的解析及应答。

一个bug是bug,多个bug能work 8052

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

上一篇: 【Python字符串操作】常用方法和高级技巧
下一篇: 【Python脚本】20个必学的Excel表格操作
HUHU爱学习
博客等级 码龄4年 1215粉丝 75原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值