__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佔用很大內存的時候, 能夠考慮從這個角度去進行內存優化, 大部分狀況是能夠取得不錯的效果.
水平有限, 歡迎拍磚!
參考文獻