__slots__是在python 2.2开始引入的一个新特性, 咱们来看一下官方给出的解释.html
This class variable can be assigned a string, iterable, or sequence of strings with variable names used by instances. If defined in a new-style class, __slots__ reserves space for the declared variables and prevents the automatic creation of __dict__ and__weakref__ for each instance.python
为声明的字段保留空间, 再也不为每一个实例生成一个__dict__和__weakref__. [参考文献1]app
python默认定义的class是能够动态添加属性的, 代码示例以下源码分析
In [1]: class Test(object): ...: pass ...: In [2]: a = Test() In [3]: a.a = 1 In [4]: a.a Out[4]: 1
能够动态地为a添加一个属性, 在class中会默认建立一个特殊的对象__dict__, 负责保存class的全部属性和方法.优化
这个__slots__主要的一个做用是减小了对内存的消耗, 这个尤为在对象数量较多的时候很是管用, 能够查看[参考文献3], 使用__slots__未做任何其余优化, 节省了9G内存.spa
示例代码以下htm
import sys from guppy import hpy class Person_(object): __slots__ = ("name", "age", "gender") def __init__(self): pass class Person(object): def __init__(self): pass if __name__ == "__main__": persons = [] for i in xrange(100000): p = Person() p.name = "name_%d" % i p.age = i p.gender = "female" persons.append(p) persons_ = [] for i in xrange(100000): p = Person_() p.name = "name_%d" % i p.age = i p.gender = "female" persons_.append(p) print "size without slots: %d" % sum([sys.getsizeof(p) for p in persons]) print "size of the __dict__ without slots: %d" % sum([sys.getsizeof(p.__dict__) for p in persons]) print "size of the __weakref__ without slots: %d" % sum([sys.getsizeof(p.__weakref__) for p in persons]) print "size with slots: %d" % sum([sys.getsizeof(p) for p in persons_]) h = hpy() print h.heap()
程序输出结果以下:对象
size without slots: 3200000 size of the __dict__ without slots: 14000000 size of the __weakref__ without slots: 800000 size with slots: 3600000 Partition of a set of 739737 objects. Total size = 32889732 bytes. Index Count % Size % Cumulative % Kind (class / dict of class) 0 100000 14 14000000 43 14000000 43 dict of __main__.Person 1 214673 29 7335252 22 21335252 65 str 2 100000 14 3600000 11 24935252 76 __main__.Person_ 3 100000 14 3200000 10 28135252 86 __main__.Person 4 209137 28 2509644 8 30644896 93 int 5 181 0 831828 3 31476724 96 list 6 7627 1 339356 1 31816080 97 tuple 7 331 0 232004 1 32048084 97 dict (no owner) 8 1670 0 120240 0 32168324 98 types.CodeType 9 73 0 110060 0 32278384 98 dict of module <95 more rows. Type e.g. '_.more' to view.>
获取内存大小的两种方法: 一种使用sys.getsizeof()方法, 一种能够采用第三方库guppy的hpy来查看, 上面的示例代码同时使用了这两种方式blog
Person是默认的new-style class, Person_是带有slots的new-style class. 为两者建立100000个对象, 来查看内存大小.内存
直接算Person_的大小总共为3.6M左右, Person的大小为3.2M. 我一直很奇怪这个为何反而大了呢?
后来发现貌似__dict__的大小没有被算进去, Person.__dict__的总大小为14M, 这样Person的总大小为17.2M, 而Person_没有__dict__属性, 总大小为3.6M, 由此能够看出, slots能够节省很是多的内存.
__dict__通常的实现都是用空间换取时间, 因此自己的内存消耗很是大, 在对象数量越多的时候越明显.
你们若是在项目中发现python占用很大内存的时候, 能够考虑从这个角度去进行内存优化, 大部分状况是能够取得不错的效果.
水平有限, 欢迎拍砖!
参考文献