python __slots__ 详解(上篇)
转自:http://blog.csdn.net/sxingming/article/details/52892640
python中的new-style class要求继承Python中的一个内建类型,一般继承object,也可以继承list或者dict等其他的内建类型。
在python新式类中,可以定义一个变量__slots__,它的作用是阻止在实例化类时为实例分配dict,
默认情况下每个类都会有一个dict,通过__dict__访问,这个dict维护了这个实例的所有属性,举例如下:
- class base(object):
- var=9 #类变量
- def __init__(self):
- pass
- b=base()
- print b.__dict__
- b.x=2 #添加实例变量
- print b.__dict__
运行结果:
{ }
{'x': 2}
可见:实例的dict只保持实例的变量,对于类的属性是不保存的,类的属性包括变量和函数。
由于每次实例化一个类都要分配一个新的dict,因此存在空间的浪费,因此有了__slots__。
__slots__是一个元组,包括了当前能访问到的属性。
当定义了slots后,slots中定义的变量变成了类的描述符,相当于java,c++中的成员变量声明,
类的实例只能拥有slots中定义的变量,不能再增加新的变量。注意:定义了slots后,就不再有dict。如下:
- class base(object):
- __slots__=('x')
- var=8
- def __init__(self):
- pass
- b=base()
- b.x=88 #添加实例变量
- print b.x
- #b.y=99 #无法添加slots之外的变量 (AttributeError: 'base' object has no attribute 'y')
- #print b.__dict__ #定义了__slots__后,就不再有__dict__ (AttributeError: 'base' object has no attribute '__dict__')
运行结果:
88
如果类变量与slots中的变量同名,则该变量被设置为readonly!!!如下:
- class base(object):
- __slots__=('y')
- y=22 # y是类变量,y与__slots__中的变量同名
- var=11
- def __init__(self):
- pass
- b=base()
- print b.y
- print base.y
- #b.y=66 #AttributeError: 'base' object attribute 'y' is read-only
运行结果:
22
22
Python是一门动态语言,可以在运行过程中,修改实例的属性和增删方法。一般,任何类的实例包含一个字典__dict__,
Python通过这个字典可以将任意属性绑定到实例上。有时候我们只想使用固定的属性,而不想任意绑定属性,
这时候我们可以定义一个属性名称集合,只有在这个集合里的名称才可以绑定。__slots__就是完成这个功能的。
- class test_slots(object):
- __slots__='x','y'
- def printHello(self):
- print 'hello!'
- class test(object):
- def printHello(self):
- print 'hello'
- print dir(test_slots) #可以看到test_slots类结构里面包含__slots__,x,y
- print dir(test)#test类结构里包含__dict__
- print '**************************************'
- ts=test_slots()
- t=test()
- print dir(ts) #可以看到ts实例结构里面包含__slots__,x,y,不能任意绑定属性
- print dir(t) #t实例结构里包含__dict__,可以任意绑定属性
- print '***************************************'
- ts.x=11 #只能绑定__slots__名称集合里的属性
- t.x=12 #可以任意绑定属性
- print ts.x,t.x
- ts.y=22 #只能绑定__slots__名称集合里的属性
- t.y=23 #可以任意绑定属性
- print ts.y,t.y
- #ts.z=33 #无法绑定__slots__集合之外的属性(AttributeError: 'test_slots' object has no attribute 'z')
- t.z=34 #可以任意绑定属性
- print t.z
运行结果:
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'printHello', 'x', 'y']
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'printHello']
**************************************
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'printHello', 'x', 'y']
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'printHello']
***************************************
11 12
22 23
34
正如上面所说的,默认情况下,Python的新式类和经典类的实例都有一个dict来存储实例的属性。这在一般情况下还不错,而且非常灵活,
乃至在程序中可以随意设置新的属性。但是,对一些在”编译”前就知道有几个固定属性的小class来说,这个dict就有点浪费内存了。
当需要创建大量实例的时候,这个问题变得尤为突出。一种解决方法是在新式类中定义一个__slots__属性。
__slots__声明中包含若干实例变量,并为每个实例预留恰好足够的空间来保存每个变量;这样Python就不会再使用dict,从而节省空间。
【使用memory_profiler模块,memory_profiler模块是在逐行的基础上,测量代码的内存使用率。尽管如此,它可能使得你的代码运行的更慢。使用装饰器@profile来标记哪个函数被跟踪。】
下面,我们看一个例子:
- from memory_profiler import profile
- class A(object): #没有定义__slots__属性
- def __init__(self,x):
- self.x=x
- @profile
- def main():
- f=[A(523825) for i in range(100000)]
- if __name__=='__main__':
- main()
运行结果,如下图:
第2列表示该行执行后Python解释器的内存使用情况,第3列表示该行代码执行前后的内存变化。
在没有定义__slots__属性的情况下,该代码共使用了20.8MiB内存。
从结果可以看出,内存使用是以MiB为单位衡量的,表示的mebibyte(1MiB = 1.05MB)
- from memory_profiler import profile
- class A(object):#定义了__slots__属性
- __slots__=('x')
- def __init__(self,x):
- self.x=x
- @profile
- def main():
- f=[A(523825) for i in range(100000)]
- if __name__=='__main__':
- main()
运行结果,如下图:
可以看到,在定义了__slots__属性的情况下,该代码共使用了6.1MiB内存,比上面的20.8MiB节省了很多内存!
综上所述,在确定了类的属性固定的情况下,可以使用__slots__来优化内存。
提醒:不要贸然进行这个优化,把它用在所有地方。这种做法不利于代码维护,而且只有生成数以千计的实例的时候才会有明显效果。
python __slots__ 详解(上篇)的更多相关文章
- Python Collections详解
Python Collections详解 collections模块在内置数据结构(list.tuple.dict.set)的基础上,提供了几个额外的数据结构:ChainMap.Counter.deq ...
- Python闭包详解
Python闭包详解 1 快速预览 以下是一段简单的闭包代码示例: def foo(): m=3 n=5 def bar(): a=4 return m+n+a return bar >> ...
- [转] Python Traceback详解
追莫名其妙的bugs利器-mark- 转自:https://www.jianshu.com/p/a8cb5375171a Python Traceback详解 刚接触Python的时候,简单的 ...
- python 数据类型详解
python数据类型详解 参考网址:http://www.cnblogs.com/linjiqin/p/3608541.html 目录1.字符串2.布尔类型3.整数4.浮点数5.数字6.列表7.元组8 ...
- Python 递归函数 详解
Python 递归函数 详解 在函数内调用当前函数本身的函数就是递归函数 下面是一个递归函数的实例: 第一次接触递归函数的人,都会被它调用本身而搞得晕头转向,而且看上面的函数调用,得到的结果会 ...
- python线程详解
#线程状态 #线程同步(锁)#多线程的优势在于可以同时运行多个任务,至少感觉起来是这样,但是当线程需要共享数据时,可能存在数据不同步的问题. #threading模块#常用方法:'''threadin ...
- python数据类型详解(全面)
python数据类型详解 目录1.字符串2.布尔类型3.整数4.浮点数5.数字6.列表7.元组8.字典9.日期 1.字符串1.1.如何在Python中使用字符串a.使用单引号(')用单引号括起来表示字 ...
- python生成器详解
1. 生成器 利用迭代器(迭代器详解python迭代器详解),我们可以在每次迭代获取数据(通过next()方法)时按照特定的规律进行生成.但是我们在实现一个迭代器时,关于当前迭代到的状态需要我们自己记 ...
- 转 python数据类型详解
python数据类型详解 目录 1.字符串 2.布尔类型 3.整数 4.浮点数 5.数字 6.列表 7.元组 8.字典 9.日期 1.字符串 1.1.如何在Python中使用字符串 a.使用单引号(' ...
随机推荐
- 当遇到Mac的Excel或者Word老是重复崩溃的时候
打开Number,新建文件然后导出为Excel.之后再用Excel打开,一切都OK了.
- CSS (二)解析CSS盒子
话说.一写博客还有些莫名的兴奋感-- 这几天一直挤时间忙于赶牛腩视频,迟到的CSS盒子.请谅解. CSS盒子,一開始听起来还有点高大上的赶脚. 后来了解之后,发现事实上非常easy理解.从功能上讲非常 ...
- [Maid] Write Tasks in Markdown with Maid
Maid enables you to write your tasks in Markdown. Create a maidfile.md or a README.mdthen add Header ...
- MTK Camera驱动移植
对于MTK Camera驱动移植一般分为四部分: 1.硬件IO口配置: 2.Camera驱动移植: 3.上电时序. 4.改动i2c控制器: 硬件电路: 1.GPIO配置 打开 mediatek\dct ...
- Android Toast小解
简单介绍:Toast英文含义是吐司,在Android中.它就像烘烤机里做好的吐司弹出来,并持续一小段时间后慢慢消失. Toast也是一个容器,能够包括各种View,并承载着它们显示. Android中 ...
- 手游产品经理初探(二)从营销角度看loading界面
近期開始写产品相关的专题,准备从细节入手去思考.总结一些不为人注意的细节地方. 今天给大家分享的是游戏里面都有的loading界面. 还是从几个在Facebook上排名靠前的Casino游戏的load ...
- 开源 免费 java CMS - FreeCMS2.1 会员3.9我的收藏
项目地址:http://www.freeteam.cn/ 我的收藏 从左側管理菜单点击我的收藏进入.在这里能够查看当前登录会员的全部收藏记录. 查看收藏 点击标题能够查看收藏内容. 删除收藏 选择收藏 ...
- hdu 5001 概率DP 图上的DP
http://acm.hdu.edu.cn/showproblem.php?pid=5001 当时一看是图上的就跪了 不敢写,也没退出来DP方程 感觉区域赛的题 一则有一个点难以想到 二则就是编码有 ...
- Spark技术内幕:Master基于ZooKeeper的High Availability(HA)源代码实现
假设Spark的部署方式选择Standalone,一个採用Master/Slaves的典型架构,那么Master是有SPOF(单点故障,Single Point of Failure).Spark能够 ...
- solr入门之solr的拼写检查功能的应用级别尝试
今天主要是收集了些拼写检查方面的资料和 尝试使用一下拼写检查的功能--=遇到了不少问题 拼写检查的四种配置眼下我仅仅算是成功了半个吧 --------------------------------- ...