Python - __slots__屬性詳解

簡(jiǎn)介

__slots__允許我們聲明并限定類成員腿准,并拒絕類創(chuàng)建__dict____weakref__屬性以節(jié)約內(nèi)存空間叙量。

Python是動(dòng)態(tài)語(yǔ)言信轿,對(duì)于普通的類,可以為類實(shí)例賦值任何屬性缝彬,這些屬性會(huì)存儲(chǔ)在__dict__中:

>>> class Student(object):
...     pass
...     
>>> Abey = Student()
>>> Abey.name = 'Abey'
>>> Abey.__dict__
{'name': 'Abey'}

這樣的特性帶來(lái)兩個(gè)問(wèn)題:

  • 數(shù)據(jù)通過(guò)字典(Hash)存儲(chǔ)所占用的空間較大
  • 如何禁止隨意生成類屬性

當(dāng)然,__slots__就能解決這兩個(gè)問(wèn)題哺眯。通過(guò)__slots__屬性限定類屬性的創(chuàng)建:

>>> class Student(object):
...     __slots__ = ('name', 'age')
...     
>>> Abey = Student()
>>> Abey.name = 'Abey'
>>> Abey.gender = 'Female'
Traceback (most recent call last):
  File "<input>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'gender'
>>> Abey.__dict__
Traceback (most recent call last):
  File "<input>", line 1, in <module>
AttributeError: 'Student' object has no attribute '__dict__'

可以看到谷浅,在定義了__slots__變量后,Student類實(shí)例已經(jīng)不能隨意創(chuàng)建不在__slots__定義內(nèi)的屬性gender,同時(shí)實(shí)例中也不再有__dict__結(jié)構(gòu)一疯。

用法

繼承樹(shù)

__slots__在繼承中有兩種表現(xiàn):

  • 子類未聲明__slots__時(shí)撼玄,不繼承父類的__slots__,即此時(shí)子類實(shí)例可以隨意賦值屬性
  • 子類聲明__slots__時(shí)墩邀,繼承父類的__slots__掌猛,即此時(shí)子類的__slots__為其自身+父類的__slots__

以下面的父類為例:

>>> class Student(object):
...     __slots__ = ('name', 'age')
...     

創(chuàng)建一個(gè)子類不聲明__slots__,該類實(shí)例可以創(chuàng)建父類__slots__限定之外的屬性gender

>>> class SubStudent(Student):
...     pass
... 
>>> Bob = SubStudent()
>>> Bob.gender = 'Male'
>>> Bob.__dict__
{'gender': 'Male'}

而創(chuàng)建一個(gè)聲明__slots__的子類眉睹,該類屬性則只能創(chuàng)建父類__slots__+自身__slots__限定的屬性:

>>> class SubStudent2(Student):
...     __slots__ = 'gender'
...     
>>> Cathy = SubStudent2()
>>> Cathy.gender = 'Female'
>>> Cathy.name = 'Cathy'
>>> Cathy.teacher = 'Mrs. Wang'
Traceback (most recent call last):
  File "<input>", line 1, in <module>
AttributeError: 'SubStudent2' object has no attribute 'teacher'

注意:子類的__slots__本身已經(jīng)繼承自父類荔茬,無(wú)需重復(fù)聲明父類已聲明的屬性。例如上例竹海,重復(fù)聲明會(huì)多占用內(nèi)存空間:

>>> class SubStudent3(Student):
...     __slots__ = ('name', 'age', 'gender')
...    
>>> from sys import getsizeof
>>> getsizeof(Student()), getsizeof(SubStudent2()), getsizeof(SubStudent3())
(56, 64, 80)

性能對(duì)比

我們?yōu)槭裁匆褂?code>__slots__呢慕蔚?

更快速地賦值屬性

參考Stack Overflow回答中給出的數(shù)據(jù):

import timeit

class Foo(object): __slots__ = 'foo',

class Bar(object): pass

slotted = Foo()
not_slotted = Bar()

def get_set_delete_fn(obj):
    def get_set_delete():
        obj.foo = 'foo'
        obj.foo
        del obj.foo
    return get_set_delete

得到測(cè)試結(jié)果為:

>>> min(timeit.repeat(get_set_delete_fn(slotted)))
0.2846834529991611
>>> min(timeit.repeat(get_set_delete_fn(not_slotted)))
0.3664822799983085

可以看到,在相同的環(huán)境(Ubuntu)下斋配,slots為Python3.5帶來(lái)了接近30%的賦值速度提升:

>>> 0.3664822799983085 / 0.2846834529991611
1.2873325658284342

節(jié)約內(nèi)存空間

由于不使用__dict__存儲(chǔ)對(duì)象的屬性坊萝,__slots__在一些場(chǎng)景下能夠節(jié)約極大的內(nèi)存空間。具體數(shù)據(jù)可以查看參考中的回答鏈接许起,不贅述十偶。

參考

[1] Usage of __slots__?, Aaron Hall, Stack Overflow

推薦閱讀

[1] Data model, Python Document
[2] python __slots__ 使你的代碼更加節(jié)省內(nèi)存, david_bj, 51CTO
[3] 使用__slots__, 廖雪峰

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市园细,隨后出現(xiàn)的幾起案子惦积,更是在濱河造成了極大的恐慌,老刑警劉巖猛频,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件狮崩,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡鹿寻,警方通過(guò)查閱死者的電腦和手機(jī)睦柴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)毡熏,“玉大人坦敌,你說(shuō)我怎么就攤上這事×》ǎ” “怎么了狱窘?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)财搁。 經(jīng)常有香客問(wèn)我蘸炸,道長(zhǎng),這世上最難降的妖魔是什么尖奔? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任搭儒,我火速辦了婚禮穷当,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘淹禾。我一直安慰自己馁菜,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布稀拐。 她就那樣靜靜地躺著火邓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪德撬。 梳的紋絲不亂的頭發(fā)上铲咨,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音蜓洪,去河邊找鬼纤勒。 笑死,一個(gè)胖子當(dāng)著我的面吹牛隆檀,可吹牛的內(nèi)容都是我干的摇天。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼恐仑,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼泉坐!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起裳仆,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤腕让,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后歧斟,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體纯丸,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年静袖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了觉鼻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡队橙,死狀恐怖坠陈,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情喘帚,我是刑警寧澤畅姊,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站吹由,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏朱嘴。R本人自食惡果不足惜倾鲫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一粗合、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧乌昔,春花似錦隙疚、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至溺蕉,卻和暖如春伶丐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背疯特。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工哗魂, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人漓雅。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓录别,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親邻吞。 傳聞我的和親對(duì)象是個(gè)殘疾皇子组题,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容