Python中__slots__屬性介紹與基本使用方法
簡(jiǎn)介
在廖雪峰的python網(wǎng)站上,他是這么說(shuō)的
python是動(dòng)態(tài)語(yǔ)言,它允許程序在執(zhí)行過(guò)程中動(dòng)態(tài)綁定屬性或者方法(使用MethodTpye)。
某個(gè)實(shí)例在執(zhí)行過(guò)程中綁定的屬性跟方法,僅在該實(shí)例中有效,其他同類(lèi)實(shí)例是沒(méi)有的。
可以通過(guò)給class綁定屬性/方法,來(lái)給所有實(shí)例綁定屬性/方法:
Student.name = '' Student.set_score = set_score
而如果使用__slots__,它僅允許動(dòng)態(tài)綁定()里面有的屬性
例如,下面這樣會(huì)報(bào)錯(cuò)
class Student():
__slots__ = ('name', 'age')
S1 = Student()
S1.name = 'Jack' # ok!
S1.score = 123 # error!
但是我覺(jué)得很奇怪,僅有這一個(gè)作用嗎?于是我再查了其他資料,發(fā)現(xiàn)這個(gè)函數(shù)可以很可觀地節(jié)約內(nèi)存,下面來(lái)一起看看詳細(xì)的介紹吧。
__slots__允許我們聲明并限定類(lèi)成員,并拒絕類(lèi)創(chuàng)建__dict__和__weakref__屬性以節(jié)約內(nèi)存空間。
Python是動(dòng)態(tài)語(yǔ)言,對(duì)于普通的類(lèi),可以為類(lèi)實(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ǔ)所占用的空間較大
- 如何禁止隨意生成類(lèi)屬性
當(dāng)然,__slots__就能解決這兩個(gè)問(wèn)題。通過(guò)__slots__屬性限定類(lèi)屬性的創(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類(lèi)實(shí)例已經(jīng)不能隨意創(chuàng)建不在__slots__定義內(nèi)的屬性gender,同時(shí)實(shí)例中也不再有__dict__結(jié)構(gòu)。
用法
繼承樹(shù)
__slots__在繼承中有兩種表現(xiàn):
- 子類(lèi)未聲明__slots__時(shí),不繼承父類(lèi)的__slots__,即此時(shí)子類(lèi)實(shí)例可以隨意賦值屬性
- 子類(lèi)聲明__slots__時(shí),繼承父類(lèi)的__slots__,即此時(shí)子類(lèi)的__slots__為其自身+父類(lèi)的__slots__
以下面的父類(lèi)為例:
>>> class Student(object):
... __slots__ = ('name', 'age')
...
創(chuàng)建一個(gè)子類(lèi)不聲明__slots__,該類(lèi)實(shí)例可以創(chuàng)建父類(lèi)__slots__限定之外的屬性gender:
>>> class SubStudent(Student):
... pass
...
>>> Bob = SubStudent()
>>> Bob.gender = 'Male'
>>> Bob.__dict__
{'gender': 'Male'}
而創(chuàng)建一個(gè)聲明__slots__的子類(lèi),該類(lèi)屬性則只能創(chuàng)建父類(lèi)__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'
注意:子類(lèi)的__slots__本身已經(jīng)繼承自父類(lèi),無(wú)需重復(fù)聲明父類(lèi)已聲明的屬性。例如上例,重復(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)槭裁匆褂胈_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%的賦值速度提升:
節(jié)約內(nèi)存空間
>>> 0.3664822799983085 / 0.2846834529991611 1.2873325658284342
由于不使用__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__ , 廖雪峰
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
Python使用中文正則表達(dá)式匹配指定中文字符串的方法示例
這篇文章主要介紹了Python使用中文正則表達(dá)式匹配指定中文字符串的方法,結(jié)合實(shí)例形式分析了Python正則匹配及字符編碼相關(guān)操作技巧,需要的朋友可以參考下2017-01-01
python神經(jīng)網(wǎng)絡(luò)Keras實(shí)現(xiàn)GRU及其參數(shù)量
這篇文章主要為大家介紹了python神經(jīng)網(wǎng)絡(luò)Keras實(shí)現(xiàn)GRU及其參數(shù)量,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05
如何使用python數(shù)據(jù)處理解決數(shù)據(jù)沖突和樣本的選取
這篇文章主要介紹了如何使用python數(shù)據(jù)處理解決數(shù)據(jù)沖突和樣本的選取,其中主要包括 實(shí)際業(yè)務(wù)數(shù)據(jù)沖突、樣本選取問(wèn)題、數(shù)據(jù)共線性等思路2021-08-08
Python 幾行代碼即可實(shí)現(xiàn)人臉識(shí)別
Python中實(shí)現(xiàn)人臉識(shí)別功能有多種方法,依賴(lài)于python膠水語(yǔ)言的特性,我們通過(guò)調(diào)用包可以快速準(zhǔn)確的達(dá)成這一目的,本文給大家分享使用Python實(shí)現(xiàn)簡(jiǎn)單的人臉識(shí)別功能的操作步驟,感興趣的朋友一起看看吧2022-02-02
python實(shí)現(xiàn)列車(chē)管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)列車(chē)管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-09-09

