__slots__节约空间
1.为什么要使用__slots__
Python 使用 dicts(hash table)缓存大量的静态资源(属性)。
我们最近在Image类中,用仅仅一行__slots__代码,改变成使用tuple储存,可以节约大量内存空间。
为啥呢?
和list相比,dict 查找和插入的速度极快,不会随着key的增加而增加;dict需要占用大量的内存,内存浪费多。
而list查找和插入的时间随着元素的增加而增加;占用空间小,浪费的内存很少。
python解释器是Cpython,这两个数据结构应该对应C的哈希表和数组。因为哈希表需要额外内存记录映射关系,而数组只需要通过索引就能计算出下一个节点的位置,所以哈希表占用的内存比数组大,也就是dict比list占用的内存更大。
2.默认情况
默认情况下,Python用一个dict来存储对象实例的属性。这在一般情况下还不错,而且非常灵活,乃至你在运行时可以随意设置新的属性。
但是,对一些在”编译”前就知道该有几个固定属性的小class来说,这个dict就有点浪费内存了。而当你把这个小浪费乘上一百万,那可就大不同了。
在Python中,你可以在class中设置__slots__,它是一个包含这些固定的属性名的list。这样Python就不会再使用dict,而且只分配这些属性的空间。
默认情况下:
改成__slots__后:
class Image(object):
__slots__ = ['id', 'name', 'age'] def __init__(self, id, name, age):
self.id = id
self.name = name
self.age = age i=Image(1,'wqbin',18)
i.__dict__
你还可以用collections.namedtuple,它允许访问参数,但只占用一个tuple的空间。这跟__slots__类似。不过我总觉得继承一个namedtuple类很奇怪。另外,如果你需要自定义初始化,你应该重载__new__而不是__init__。
警告:不要贸然进行这个优化,把它用在所有地方。这种做法不利于代码维护,而且只有当你有数以千计的实例的时候才会有明显效果。
译注:作者在评论中关于”不利于代码维护“的说法:
webreac:我觉得__slots__关键字不只是速度优化(注:这里应该是内存优化),也是类字段名的一个可靠”文档“。这有利于代码维护。为什么你觉得它不好?
Ben Hoyt(作者):有趣的说法——我不确定应不应该把__slots__作为文档。不过的确是不错的注意。我之前这么说的原因是,你需要对字段名”定义“两次(不够DRY)。namedtuple也类似
3.空间节省效果
class Foobar(object):
__slots__=('x')
def __init__(self, x):
self.x = x @profile
def main():
f = [Foobar(42) for i in range(1000000)] if __name__ == "__main__":
main()
class Foobar(object):
def __init__(self, x):
self.x = x @profile
def main():
f = [Foobar(42) for i in range(1000000)] if __name__ == "__main__":
main()
100百万个实例化对象的内存占用从208M降低到93M
__slots__节约空间的更多相关文章
- python的__slots__节约内存的魔法;检查python每一行代码内存占用情况的工具
在Python中,每个类都有实例属性.默认情况下Python用一个字典来保存一个对象的实例属性.这非常有用,因为它允许我们在运行时去设置任意的新属性. 然而,对于有着已知属性的小类来说,它可能是个瓶颈 ...
- leetcode 645. Set Mismatch——凡是要节约空间的题目 都在输入数据上下功夫 不要担心破坏原始的input
The set S originally contains numbers from 1 to n. But unfortunately, due to the data error, one of ...
- 以太网EMC(浪涌)中心抽头方案(节约空间)
- 循环队列 & 栈的共用空间
循环队列 非常好的数据结构,充分利用率空间,可以用于网络端存储socket消息! /*************************************** 作者: 未闻花语 版本: v1.0 ...
- JVM体系结构之七:持久代、元空间(Metaspace) 常量池==了解String类的intern()方法、常量池介绍、常量池从Perm-->Heap
一.intern()定义及使用 相信绝大多数的人不会去用String类的intern方法,打开String类的源码发现这是一个本地方法,定义如下: public native String inter ...
- oracle 碎片管理和数据文件resize释放表空间和磁盘空间(以及sys.wri$_optstat_histgrm_history过大处理)
随着互联网的快速发展,各行各业的数据量也是与日俱增,而数据库的数据量也是直线增长,但是,如果表DML太多,则可能会在高水位线以下出现太多空白. 因此,只能将数据文件缩小到高水位线,因为高水位线以下有一 ...
- 告别被拒,如何提升iOS审核通过率(上篇)
iOS审核一直是每款移动产品上架苹果商店时面对的一座大山,每次提审都像是一次漫长而又悲壮的旅行,经常被苹果拒之门外,无比煎熬.那么问题来了,我们有没有什么办法准确把握苹果审核准则,从而提升审核的通过率 ...
- 纸箱堆叠 bzoj 2253
纸箱堆叠 (1s 128MB) box [问题描述] P 工厂是一个生产纸箱的工厂.纸箱生产线在人工输入三个参数 n, p, a 之后,即可自动化生产三边边长为 (a mod P, a^2 mod p ...
- 爬虫入门——01
1. 引言 从今天开始系统的学习网络爬虫.写这篇博客的目的在于,一来记录下自己的学习过程:二来希望可以给像我一样不懂爬虫但又对爬虫十分感兴趣的人带来一些帮助. 昨天去图书馆找有关爬虫书 ...
随机推荐
- Linux札记
1. tar.gz 压缩命令:tar -zcvf 压缩文件名.tar.gz 被压缩文件名 解压命令:tar -zxvf 压缩文件名.tar.gz
- Linux文件属性之时间戳及文件名知识详解
ls -lhi 7.8.9三列是时间(默认是修改时间) modify 修改时间 -----mtime 一般是修改文件内容 change 改变时间----ctime 文件的 ...
- Nuxt的动态路由及路由校验入门
其实动态路由就是带参数的路由.比如我们现在新闻模块下面有很多新闻详情页,这时候就需要动态路由的帮助了. 新闻详细页面我们在news文件夹下面新建了_id.vue的文件,以下划线为前缀的Vue文件就是动 ...
- ./configure配置的参数 交叉编译 host,build target的含义
交叉编译 host,build target的含义:build就是你正在使用的机器,host就是你编译好的程序可以运行的平台,target就是你编译的程序可以处理的平台.这个 build和host比较 ...
- 大数据之Zookeeper概述
Zookeeper概述 Zookeeper是一个开放源码的分布式应用程序协调服务,是 Google的Chubby一个开源的实现,是 Hadoop和 HBASE的重要组件.主要解决分布式应用一致性问题. ...
- 拨开Python迷雾
Python方向及能力要求 web就业方向:Python基础.Python高级.前端开发. web开发爬虫方向:Python基础.Python高级.前端开发.web开发. 爬虫开发数据挖掘/分析方 ...
- 15条SQLite3语句
15条SQLite3语句 转自:http://www.thegeekstuff.com/2012/09/sqlite-command-examples/ SQLite3 is very light ...
- Python算法题(二)——国际象棋棋盘(排列组合问题,最小的K个数)
题目一(输出国际象棋棋盘) 分析: 用i控制行,j来控制列,根据i+j的和的变化来控制输出黑方格,还是白方格. 主要代码: for i in range(8): for j in range(8 ...
- 客户端注册Cannot execute request on any known server解决
在对eureka注册中心服务端添加安全验证后,新版本springcloud出现一个问题就是,在客户端注册到服务中心时报了一个错:Cannot execute request on any known ...
- 5 java 笔记
1 建议不要在循环体内修改循环变量的值 2 java语言没有提供goto语句来控制程序的跳转 2 java语言同样也提供了continue和break关键字来控制程序的循环结构 3 java中的标签 ...