標籤:

Python __slots__ 詳解

Python老鳥都應該看過那篇非常有吸引力的 Saving 9 GB of RAM with Python』s __slots__ 文章,作者使用了__slots__讓內存佔用從25.5GB降到了16.2GB。在當時來說,這相當於用一個非常簡單的方式就降低了30%的內存使用,著實驚人。作者並沒有提到他的業務特點和代碼,那我們就基於《fluent python》中的例子來驗證下是不是有這麼厲害:

from __future__ import print_functionnimport resourcennnclass A(object):n def __init__(self):n self.a = stringn self.b = 10n self.c = Truennnclass B(object):n __slots__ = [a, b, c]n def __init__(self):n self.a = stringn self.b = 10n self.c = Truennndef test(cls):n mem_init = resource.getrusage(resource.RUSAGE_SELF).ru_maxrssn l = []n for i in range(500000):n l.append(cls())n mem_final = resource.getrusage(resource.RUSAGE_SELF).ru_maxrssn del ln print(Class: {}:n.format(getattr(cls, __name__)))n print(Initial RAM usage: {:14,}.format(mem_init))n print( Final RAM usage: {:14,}.format(mem_final))n print(- * 20)nnnif __name__ == __main__:n import sysn test(globals()[sys.argv[1].upper()])n

我們分別跑一下這2個類:

? python mem_test.py anClass: A:nnInitial RAM usage: 4,890,624n Final RAM usage: 200,454,144n--------------------nn? python mem_test.py bnClass: B:nnInitial RAM usage: 4,919,296n Final RAM usage: 60,235,776n

2種方法初始內存略有差別,但是由於這個差別和總內存量相比太小而忽略不計,結論就是:

使用slots可以讓內存使用減少3.5倍!!# 通過 (200 - 4) / ((60 - 4) * 1.0) 計算得來

那麼用slot就是非非常那個有必要嗎?事實上500000個實例這種機會非常少見,用不用完全根據業務來決定,並不要以偏概全。因為(敲黑板了哈)使用__slots__也是有副作用的:

1. 每個繼承的子類都要重新定義一遍__slots__n2. 實例只能包含哪些在__slots__定義的屬性,這對寫程序的靈活性有影響,比如你由於某個原因新網給instance設置一個新的屬性,比如instance.a = 1, 但是由於a不在__slots__裡面就直接報錯了,你得不斷地去修改__slots__或者用其他方法迂迴的解決n3. 實例不能有弱引用(weakref)目標,否則要記得把__weakref__放進__slots__n

第三點有點難理解,我寫個例子看看吧:

In [2]: %pycat ref_example.py nfrom weakref import refnnclass A(object):n __slots__ = [b]n def __init__(self):n self.b = 1nnnclass B(object):n __slots__ = [b, __weakref__]n def __init__(self):n self.b = 1nnIn [3]: from ref_example import *nnIn [4]: a = A()nnIn [5]: r = ref(a)n---------------------------------------------------------------------------nTypeError Traceback (most recent call last)n<ipython-input-6-75a6d689c8b3> in <module>()n----> 1 r = ref(a)nnTypeError: cannot create weak reference to A objectnnIn [6]: b = B()nnIn [7]: r = ref(b)nnIn [8]: rnOut[8]: <weakref at 0x109199578; to B at 0x10919f890>n

所以實例不超過萬級別的類,__slots__是不太值得使用的。

PS:《fluent python》比我狠,說的是小於百萬級別實例不值得使用。

無恥的廣告:《Python Web開發實戰》上市了!

歡迎關注本人的微信公眾號獲取更多Python相關的內容(也可以直接搜索「Python之美」):


推薦閱讀:

如何看待將Python代碼轉換成Go代碼並進一步編譯的 Grumpy 項目?
寫了一個scrapy爬蟲,為什麼運行提示找不到Douban.items這個模塊??
Python unittest單元測試框架 斷言assert
Python練習第四題,批量修改圖片解析度
Python是最好的編程語言嗎?

TAG:Python |