python 類 __slots__ 可限制添加屬性和優化減少內存佔用

一、如何限制屬性

1.給類或者示例添加屬性和方法

正常情況下,當我們定義了一個class,創建了一個class的實例後,我們可以給該實例綁定任何屬性和方法,對於class本身也是一樣的在這裏插入圖片描述

2.使用__slots__

如果先要對class和實例加以限制,可以在定義class的時候,定義一個__slots__,來限制能夠添加的屬性:
在這裏插入圖片描述
這麼做之後,沒在__slots__裏面標記好的屬性就不能隨便添加到類或者示例中了

二、如何節省內存

1.方法

在默認情況下,Python的新類和舊類的實例都有一個字典來存儲屬性值。這對於那些沒有實例屬性的對象來說太浪費空間了,當需要創建大量實例的時候,這個問題變得尤爲突出。
因此這種默認的做法可以通過在新式類中定義了一個__slots__屬性從而得到了解決。__slots__聲明中包含若干實例變量,併爲每個實例預留恰好足夠的空間來保存每個變量,因此沒有爲每個實例都創建一個字典,從而節省空間。

2.原理

和list相比,dict 查找和插入的速度極快,不會隨着key的增加而增加;dict需要佔用大量的內存,內存浪費多。而list查找和插入的時間隨着元素的增加而增加;佔用空間小,浪費的內存很少。python解釋器是Cpython,這兩個數據結構應該對應C的哈希表和數組。因爲哈希表需要額外內存記錄映射關係,而數組只需要通過索引就能計算出下一個節點的位置,所以哈希表佔用的內存比數組大,也就是dict比list佔用的內存更大。

3.測試

是騾子是馬,牽出來溜溜就知道
首先安裝memory_profiler

pip install memory_profiler

編寫測試腳本

from memory_profiler import profile
class Foobar():
    def __init__(self, x):
        self.xx = x

@profile
def main():
    f = [Foobar(i) for i in range(1000000)]


if __name__ == '__main__':
    main()

運行結果
在這裏插入圖片描述
重新通過__slots__來實現

from memory_profiler import profile
class Foobar():
    __slots__ = ['xx',]
    def __init__(self, x):
        self.xx = x

@profile
def main():
    f = [Foobar(i) for i in range(1000000)]


if __name__ == '__main__':
    main()

結果:
在這裏插入圖片描述
實測在mac上,用pycharm跑節省了大約一半的內存

4.總結

在確定類的屬性值固定的情況下,可以使用__slots__方式對內存進行優化。但是這項技術不應該被濫用於靜態類或者其他類似場合,那不是python程序的精神所在。

參考:https://m.jb51.net/article/146854.htm

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章