簡介
在廖雪峰的python網(wǎng)站上,他是這么說的
python是動(dòng)態(tài)語言,它允許程序在執(zhí)行過程中動(dòng)態(tài)綁定屬性或者方法(使用MethodTpye)。
某個(gè)實(shí)例在執(zhí)行過程中綁定的屬性跟方法,僅在該實(shí)例中有效,其他同類實(shí)例是沒有的。
可以通過給class綁定屬性/方法,來給所有實(shí)例綁定屬性/方法:
Student.name = ''Student.set_score = set_score
而如果使用__slots__,它僅允許動(dòng)態(tài)綁定()里面有的屬性
例如,下面這樣會報(bào)錯(cuò)
class Student():__slots__ = ('name', 'age')S1 = Student()S1.name = 'Jack' # ok!S1.score = 123 # error!但是我覺得很奇怪,僅有這一個(gè)作用嗎?于是我再查了其他資料,發(fā)現(xiàn)這個(gè)函數(shù)可以很可觀地節(jié)約內(nèi)存,下面來一起看看詳細(xì)的介紹吧。
__slots__允許我們聲明并限定類成員,并拒絕類創(chuàng)建__dict__和__weakref__屬性以節(jié)約內(nèi)存空間。
Python是動(dòng)態(tài)語言,對于普通的類,可以為類實(shí)例賦值任何屬性,這些屬性會存儲在__dict__中:
>>> class Student(object):... pass... >>> Abey = Student()>>> Abey.name = 'Abey'>>> Abey.__dict__{'name': 'Abey'}這樣的特性帶來兩個(gè)問題:
當(dāng)然,__slots__就能解決這兩個(gè)問題。通過__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)。
用法
繼承樹
__slots__在繼承中有兩種表現(xiàn):
以下面的父類為例:
>>> 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)繼承自父類,無需重復(fù)聲明父類已聲明的屬性。例如上例,重復(fù)聲明會多占用內(nèi)存空間:
>>> class SubStudent3(Student):... __slots__ = ('name', 'age', 'gender')... >>> from sys import getsizeof>>> getsizeof(Student()), getsizeof(SubStudent2()), getsizeof(SubStudent3())(56, 64, 80)性能對比
我們?yōu)槭裁匆褂胈_slots__呢?
更快速地賦值屬性
參考Stack Overflow回答中給出的數(shù)據(jù):
import timeitclass Foo(object): __slots__ = 'foo',class Bar(object): passslotted = 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
得到測試結(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帶來了接近30%的賦值速度提升:
節(jié)約內(nèi)存空間
>>> 0.3664822799983085 / 0.28468345299916111.2873325658284342
由于不使用__dict__存儲對象的屬性,__slots__在一些場景下能夠節(jié)約極大的內(nèi)存空間。具體數(shù)據(jù)可以查看參考中的回答鏈接,不贅述。
參考
[1] Usage of __slots__? , Aaron Hall, Stack Overflow
推薦閱讀
[1] Data model , Python Document
[2] 使用__slots__ , 廖雪峰
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網(wǎng)的支持。
新聞熱點(diǎn)
疑難解答
圖片精選