详解python 内存优化


Posted in Python onAugust 17, 2020

写在之前

围绕类的话题,说是说不完的,仅在特殊方法,除了我们在前面遇到过的 __init__(),__new__(),__str__() 等之外还有很多。虽然它们只是在某些特殊的场景中才会用到,但是学会它们却可以成为你熟悉这门语言路上的铺路石。

所以我会在试图介绍一些「黑魔法」,让大家多多感受一下 Python 的魅力所在,俗话说「艺多不压身」就是这个道理了。

内存优化

首先先让我们从复习前面的类属性和实例属性的知识来引出另一个特殊方法:

>>> class Sample:
...   name = 'rocky'
...

就像前面的文章我们所说的,每个类都有一个 __dict__() 属性,它包含了当前类的类属性:

>>> Sample.__dict__
mappingproxy({'__module__': '__main__', 'name': 'rocky', '__dict__': <attribute '__dict__' of 'Sample' objects>, '__weakref__': <attribute '__weakref__' of 'Sample' objects>, '__doc__': None})
>>> Sample.name
'rocky'

同样,如果我们创建了实例,每个实例也有一个 __dict__ 属性,它里面就是当前的实例属性:

>>> a = Sample()
>>> a.__dict__
{}
>>> a.age = 23
>>> a.__dict__
{'age': 23}

上面的操作可以看出,当实例刚刚创建的时候,__dict__ 是空的,只有创建了实例属性以后,它才包含其内容。实例的 __dict__ 和类的 __dict__ 是有所区别的,即实例属性和类属性是不同的。

从理论上来说,我们可以根据一个类创建无数的实例,新建一个实例以后,又创建了一个新的 __dict__,这将是一个很可怕的事情,虽然每个 __dict__ 所占的内存空间很小,当然这件事事实上是不会出现的。但是程序不能建立在这种不可靠的猜测的基础上,程序要对过程有明确的控制。

所以就要有一种方法能够控制 __dict__,于是「__slots__」应运而生。

>>> class Nature:
... __slots__ = ('tree','flower')
... 
>>> dir(Nature)
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'flower', 'tree']

我们仔细来看 dir() 的结果,发现 __dict__ 属性没有了,也就是说 __slots__ 把 __dict__ 挤出去了,它进入了类的属性。

>>> Nature.__slots__
('tree', 'flower')

从这里可以看出,类 Nature 有且仅有两个属性。从类的角度来看,其类属性只有这两个;从实例的角度来看,其实例属性也只有这两个。

>>> Nature.tree = 'liushu'
>>> Nature.tree
'liushu'
>>> Nature.tree = 'lishu'
>>> Nature.tree
'lishu'

通过类可以对属性进行赋值和修改,这个似乎和以前的类属性没有什么区别,别着急,继续往下看就看到区别了:

>>> x = Nature()
>>> x.__slots__
('tree', 'flower')
>>> y = Nature()
>>> y.__slots__
('tree', 'flower')
>>> id(x.__slots__)
4531629384
>>> id(y.__slots__)
4531629384

你看,实例化以后,实例的 __slots__ 和类的 __slots__ 完全一样,这跟前面的 __dict__ 大不一样了。并且我们建立了两个实例,结果发现两个实例的 __slots__ 在内存中居然是一个,或者可以说是增加实例时 __slots__ 并不增加。

>>> x.tree
'lishu'
>>> y.tree
'lishu'

既然类属性已经赋值,那么通过任何一个实例属性都能得到同样的值,不过这时候不能通过实例修改此属性的值。

>>> x.tree = 'taoshu'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Nature' object attribute 'tree' is read-only

对实例属性来说,类的静态数据是只读的,不能修改,只有通过类属性才能修改。但对于尚未赋值的属性,能够通过实例赋值。

>>> x.flower = 'rose'
>>> x.flower
'rose'
>>> x.flower = 'moli'

显然通过实例操作的属性,也能够通过实例修改,但是实例属性的值并不能够修改类属性的值

Nature.flower
<member 'flower' of 'Nature' objects>

由上面可以看出,实例属性的值并没有传回给类属性,也可以理解为新建了一个同名字的实例属性,如果再给类属性赋值的话,则会像下面一样:

>>> Nature.flower = 'huaihua'
>>> x.flower
'huaihua'

类属性对实例属性具有决定作用,对实例而言,通过类所定义的属性都是只读的。

__slots__ 已经把实例属性牢牢的看管起来,只能是指定的属性,如果想要增加属性的话,只能通过类属性来实现,所以 __slots__ 的一个重要作用就是优化了内存。

写在之后

当然了,__slots__ 还能加快属性加载速度,这个不是本文的重点,所以不做过多的介绍,感兴趣的可以去 Google 一下。

今天的文章就到这里啦,明天讲一下「属性拦截」,又是新的一周,燥起来!

如果你觉得文章对你有帮助的话,欢迎点赞转发,让更多的人看到,谢谢啦。

The end。

以上就是详解python 内存优化的详细内容,更多关于python 内存优化的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
pycharm 使用心得(六)进行简单的数据库管理
Jun 06 Python
python实现在windows服务中新建进程的方法
Jun 30 Python
遗传算法之Python实现代码
Oct 10 Python
对PyTorch torch.stack的实例讲解
Jul 30 Python
对Pandas DataFrame缺失值的查找与填充示例讲解
Nov 06 Python
python实现简易学生信息管理系统
Apr 05 Python
Anaconda+Pycharm环境下的PyTorch配置方法
Mar 13 Python
Python文件读写w+和r+区别解析
Mar 26 Python
Python操作dict时避免出现KeyError的几种解决方法
Sep 20 Python
python读取excel数据绘制简单曲线图的完整步骤记录
Oct 30 Python
matplotlib相关系统目录获取方式小结
Feb 03 Python
OpenCV中resize函数插值算法的实现过程(五种)
Jun 05 Python
浅谈如何使用python抓取网页中的动态数据实现
Aug 17 #Python
详解Python 中的容器 collections
Aug 17 #Python
Python 解析库json及jsonpath pickle的实现
Aug 17 #Python
Python实现爬取网页中动态加载的数据
Aug 17 #Python
Python 如何操作 SQLite 数据库
Aug 17 #Python
Python使用正则表达式实现爬虫数据抽取
Aug 17 #Python
Python 通过正则表达式快速获取电影的下载地址
Aug 17 #Python
You might like
Discuz Uchome ajaxpost小技巧
2011/01/04 PHP
php中url函数介绍及使用示例
2014/02/13 PHP
PHP实现的抓取小说网站内容功能示例
2019/06/27 PHP
JavaScript 计算当天是本年本月的第几周
2009/03/22 Javascript
Prototype 学习 工具函数学习($A方法)
2009/07/12 Javascript
js function定义函数使用心得
2010/04/15 Javascript
js数据验证集合、js email验证、js url验证、js长度验证、js数字验证等简单封装
2010/05/15 Javascript
深入理解JavaScript高级之词法作用域和作用域链
2013/12/10 Javascript
js继承call()和apply()方法总结
2014/12/08 Javascript
Extjs 点击复选框在表格中增加相关信息行
2016/07/12 Javascript
Ubuntu系统下Angularjs开发环境安装
2016/09/01 Javascript
AngularJS 指令的交互详解及实例代码
2016/09/14 Javascript
jQuery.Form上传文件操作
2017/02/05 Javascript
详解vue-router传参的两种方式
2018/09/10 Javascript
详解express使用vue-router的history踩坑
2019/06/05 Javascript
layui富文本编辑器前端无法取值的解决方法
2019/09/18 Javascript
一文读懂vue动态属性数据绑定(v-bind指令)
2020/07/20 Javascript
[52:22]EG vs VG Supermajor小组赛B组 BO3 第一场 6.2
2018/06/03 DOTA
[01:03:03]VP vs Mineski 2018国际邀请赛淘汰赛BO3 第一场 8.22
2018/08/23 DOTA
[55:39]DOTA2-DPC中国联赛 正赛 VG vs LBZS BO3 第二场 1月19日
2021/03/11 DOTA
Linux下Python获取IP地址的代码
2014/11/30 Python
Python的SQLalchemy模块连接与操作MySQL的基础示例
2016/07/11 Python
PyTorch 对应点相乘、矩阵相乘实例
2019/12/27 Python
美国领先的奢侈美容零售商:Bluemercury
2017/07/26 全球购物
中国旅游网站:途牛旅游网
2019/09/29 全球购物
用JAVA SOCKET编程,读服务器几个字符,再写入本地显示
2012/11/25 面试题
Java工程师面试集锦之Spring框架
2013/06/16 面试题
生产部岗位职责范文
2014/02/07 职场文书
电大毕业个人生自我鉴定
2014/03/26 职场文书
学校师德承诺书
2014/05/23 职场文书
普通话演讲稿
2014/09/03 职场文书
合伙经营协议书范本
2014/09/13 职场文书
单位实习介绍信
2015/05/05 职场文书
晚会主持人开场白台词
2015/05/28 职场文书
Spring Boot 实现敏感词及特殊字符过滤处理
2021/06/29 Java/Android
Redis之RedisTemplate配置方式(序列和反序列化)
2022/03/13 Redis