Python中的__slots__示例詳解
前言
相信Python老鳥都應(yīng)該看過(guò)那篇非常有吸引力的Saving 9 GB of RAM with Python's slots 文章,作者使用了__slots__讓內(nèi)存占用從25.5GB降到了16.2GB。在當(dāng)時(shí)來(lái)說(shuō),這相當(dāng)于用一個(gè)非常簡(jiǎn)單的方式就降低了30%的內(nèi)存使用,著實(shí)驚人。作者并沒(méi)有提到他的業(yè)務(wù)特點(diǎn)和代碼,那我們就基于《fluent python》中的例子來(lái)驗(yàn)證下是不是有這么厲害:
from __future__ import print_function
import resource
class A(object):
def __init__(self):
self.a = 'string'
self.b = 10
self.c = True
class B(object):
__slots__ = ['a', 'b', 'c']
def __init__(self):
self.a = 'string'
self.b = 10
self.c = True
def test(cls):
mem_init = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
l = []
for i in range(500000):
l.append(cls())
mem_final = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
del l
print('Class: {}:\n'.format(getattr(cls, '__name__')))
print('Initial RAM usage: {:14,}'.format(mem_init))
print(' Final RAM usage: {:14,}'.format(mem_final))
print('-' * 20)
if __name__ == '__main__':
import sys
test(globals()[sys.argv[1].upper()])
我們分別跑一下這2個(gè)類:
❯ python mem_test.py a Class: A: Initial RAM usage: 4,890,624 Final RAM usage: 200,454,144 -------------------- ❯ python mem_test.py b Class: B: Initial RAM usage: 4,919,296 Final RAM usage: 60,235,776
2種方法初始內(nèi)存略有差別,但是由于這個(gè)差別和總內(nèi)存量相比太小而忽略不計(jì),結(jié)論就是:
使用slots可以讓內(nèi)存使用減少3.5倍?。? 通過(guò) (200 - 4) / ((60 - 4) * 1.0) 計(jì)算得來(lái)
那么用slot就是非非常那個(gè)有必要嗎?事實(shí)上500000個(gè)實(shí)例這種機(jī)會(huì)非常少見,用不用完全根據(jù)業(yè)務(wù)來(lái)決定,并不要以偏概全。因?yàn)椋ㄇ煤诎辶斯┦褂胈_slots__也是有副作用的:
- 每個(gè)繼承的子類都要重新定義一遍__slots__
- 實(shí)例只能包含哪些在__slots__定義的屬性,這對(duì)寫程序的靈活性有影響,比如你由于某個(gè)原因新網(wǎng)給instance設(shè)置一個(gè)新的屬性,比如instance.a = 1, 但是由于a不在__slots__里面就直接報(bào)錯(cuò)了,你得不斷地去修改__slots__或者用其他方法迂回的解決
- 實(shí)例不能有弱引用(weakref)目標(biāo),否則要記得把__weakref__放進(jìn)__slots__
第三點(diǎn)有點(diǎn)難理解,我寫個(gè)例子看看吧:
In [2]: %pycat ref_example.py from weakref import ref class A(object): __slots__ = ['b'] def __init__(self): self.b = 1 class B(object): __slots__ = ['b', '__weakref__'] def __init__(self): self.b = 1 In [3]: from ref_example import * In [4]: a = A() In [5]: r = ref(a) --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-6-75a6d689c8b3> in <module>() ----> 1 r = ref(a) TypeError: cannot create weak reference to 'A' object In [6]: b = B() In [7]: r = ref(b) In [8]: r Out[8]: <weakref at 0x109199578; to 'B' at 0x10919f890>
所以實(shí)例不超過(guò)萬(wàn)級(jí)別的類,__slots__是不太值得使用的。
PS: 《fluent python》比我狠,說(shuō)的是小于百萬(wàn)級(jí)別實(shí)例不值得使用。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
解決Jupyter Notebook “signal only works&nb
這篇文章主要介紹了解決Jupyter Notebook “signal only works in main thread“問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01
使用Playwright進(jìn)行視覺回歸測(cè)試詳解
這篇文章主要介紹了使用Playwright進(jìn)行視覺回歸測(cè)試詳解,視覺回歸測(cè)試是一種軟件測(cè)試技術(shù),專注于檢測(cè)Web應(yīng)用程序或網(wǎng)站的用戶界面中的視覺變化和差異,需要的朋友可以參考下2023-08-08
scrapy框架中用ssh連接遠(yuǎn)程服務(wù)器的實(shí)現(xiàn)
本文主要介紹了scrapy?框架中用ssh連接遠(yuǎn)程服務(wù)器的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01
Python實(shí)現(xiàn)ssh批量登錄并執(zhí)行命令
本篇文章主要是介紹了Python實(shí)現(xiàn)ssh批量登錄并執(zhí)行命令,有一些任務(wù)可以進(jìn)行批量完成,Python就可以完成,有需要的同學(xué)可以了解一下。2016-10-10
Python編程使用Selenium模擬淘寶登錄實(shí)現(xiàn)過(guò)程
這篇文章主要介紹了Python編程使用Selenium模擬淘寶登錄的實(shí)現(xiàn)過(guò)程示例及解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2021-10-10
Pandas DataFrame replace替換后無(wú)效的解決
這篇文章主要介紹了Pandas DataFrame replace替換后無(wú)效的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08
如何利用Python matplotlib繪制雷達(dá)圖
這篇文章主要給大家介紹了關(guān)于如何利用Python matplotlib繪制雷達(dá)圖的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
python3實(shí)現(xiàn)windows下同名進(jìn)程監(jiān)控
這篇文章主要為大家詳細(xì)介紹了python3實(shí)現(xiàn)windows下同名進(jìn)程監(jiān)控,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-06-06

