Python __slots__的使用方法
準(zhǔn)備
正常情況下,創(chuàng)建class的實(shí)例后,可以給該實(shí)例綁定任何屬性和方法,這就是動(dòng)態(tài)語(yǔ)言的靈活性。首先定義一個(gè)class
class A(object): pass
然后創(chuàng)建一個(gè)實(shí)例,并給實(shí)例添加屬性和方法。
a = A() print a.__dict__ #{} A.name = 'xiaoming' #動(dòng)態(tài)的給實(shí)例綁定屬性,其實(shí)例屬性會(huì)保存到實(shí)例的__dict__中 print a.__dict__ #{'name': 'xiaoming'} f = lambda :100 a.fun = f print a.__dict__ #{'fun': <function <lambda> at>, 'name': 'xiaoming'}
此時(shí)的name屬性和fun()方法只有實(shí)例a能使用,類(lèi)A的其他實(shí)例不能使用,如果想讓類(lèi)A的所有實(shí)例都能使用,我們需要給類(lèi)A綁定方法
print A.__dict__ #... f = lambda :100 A.fun = f print A.__dict__ #... + 'fun': <function <lambda> at 0x0000000003582978>
此時(shí),類(lèi)A的所有實(shí)例就能使用方法fun()了。
通常情況下,上面的fun()方法應(yīng)該定義在class中,但動(dòng)態(tài)綁定允許在程序運(yùn)行的過(guò)程中動(dòng)態(tài)的給class增加功能,這在靜態(tài)語(yǔ)言中很難實(shí)現(xiàn),這也是動(dòng)態(tài)語(yǔ)言的優(yōu)點(diǎn)。
__slots__
如果在一個(gè)類(lèi)中定義了__slots__屬性,那么這個(gè)類(lèi)的實(shí)例將不會(huì)擁有__dict__屬性,沒(méi)有__dict__的實(shí)例也就不能添加實(shí)例屬性了。簡(jiǎn)單來(lái)說(shuō),__slots__的作用就是阻止類(lèi)在實(shí)例化時(shí)為實(shí)例分配__dict__屬性,限制該實(shí)例能添加的屬性。
作用
通常情況下實(shí)例使用__dict__來(lái)存儲(chǔ)自己的屬性,它允許實(shí)例動(dòng)態(tài)地添加或刪除屬性。然而,對(duì)一些在編譯期就已經(jīng)知道有什么變量的類(lèi)或者不允許動(dòng)態(tài)添加變量的類(lèi)來(lái)說(shuō),它們并不需要?jiǎng)討B(tài)地添加變量。如果想要限制實(shí)例屬性,不想讓它動(dòng)態(tài)添加屬性怎么辦?比如我們只允許對(duì)A的實(shí)例添加name和age屬性。
為了達(dá)到上述目的,Python允許在定義class的時(shí)候,定義一個(gè)__slots__變量,來(lái)限制該class的實(shí)例能添加的屬性。
class A(object): __slots__ = ('age','name') a = A() a.name = 'xiaoming' a.age = 10 a.id = 123456 #error AttributeError: 'A' object has no attribute 'id'
由于id不在__slots__中,所以實(shí)例不能添加id屬性。任何試圖給實(shí)例添加一個(gè)其名不在__slots__中的屬性都將觸發(fā)AttributeError異常。
實(shí)現(xiàn)原理
__slots__中的變量是類(lèi)屬性,類(lèi)型為數(shù)據(jù)描述符。
#!/usr/bin/python # -*- coding: utf-8 -*- class Foo(object): __slots__ = ('age','name') def __init__(self,age = 0): self.age = age s = Foo.__dict__['age'] print s #<member 'age' of 'Foo' objects> print type(s) #<type 'member_descriptor'> '''證明為數(shù)據(jù)描述符''' print '__get__' in dir(s) #True print '__set__' in dir(s) #True
__slots__中的變量雖然是類(lèi)屬性,但是不同實(shí)例之間互不影響。因?yàn)槊枋龇椒ǖ囊粋€(gè)參數(shù)為實(shí)例,建立一個(gè)實(shí)例和值的映射還是很簡(jiǎn)單的。如果不懂,建議看描述符 。
f1 = Foo(1) f2 = Foo(2) print f1.age,f2.age #1,2 print Foo.__dict__['age'].__get__(f1) #1 print Foo.__dict__['age'].__get__(f2) #2
__slots__的好處
如果類(lèi)沒(méi)有定義__slots__ ,該類(lèi)的實(shí)例會(huì)有__dict__屬性,通過(guò)__dict__可修改,刪除,增加實(shí)例屬性。
如果類(lèi)定義了__slots__,該類(lèi)的實(shí)例不會(huì)有__dict__屬性。實(shí)例中的__dict__屬性是非常耗內(nèi)存的,當(dāng)創(chuàng)建上百萬(wàn)個(gè)實(shí)例的時(shí)候,所有實(shí)例的__dict__會(huì)占用一塊很大的內(nèi)存。沒(méi)有了__dict__的實(shí)例也就不能動(dòng)態(tài)添加屬性,只需分配固定的空間來(lái)存儲(chǔ)已知的屬性。因此使用__slots__的類(lèi)能節(jié)省一部分內(nèi)存開(kāi)銷(xiāo)。
對(duì)于不需要?jiǎng)討B(tài)添加屬性的類(lèi)來(lái)說(shuō),應(yīng)使用__slots__。
注意:不用過(guò)早的使用這個(gè)方法,它不利于代碼維護(hù),當(dāng)實(shí)例很多(上千萬(wàn))時(shí),這種優(yōu)化才有明顯的效果。在實(shí)際使用中,__slots__從未被當(dāng)作一種安全的特性來(lái)使用,它是對(duì)內(nèi)存和執(zhí)行速度的一種性能優(yōu)化。使用__slots__的類(lèi)的實(shí)例不再使用字典來(lái)存儲(chǔ)實(shí)例屬性,而是使用基于數(shù)組的一種更加緊湊的數(shù)據(jù)結(jié)構(gòu),所以當(dāng)實(shí)例很多時(shí),使用__slots__可以顯著減少內(nèi)存占用和執(zhí)行時(shí)間。
class A(object): pass class B(object): __slots__ = ('age','name') a = A() b = B()
沒(méi)有__slots__的類(lèi)和實(shí)例
print a.__dict__ #{} print A.__dict__ ''' {'__dict__': <attribute '__dict__' of 'A' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None} '''
有__slots__的類(lèi)和實(shí)例
print b.__dict__ #AttributeError: 'B' object has no attribute '__dict__' print B.__dict__ ''' {'age': <member 'age' of 'B' objects>, '__module__': '__main__', '__doc__': None, '__slots__': ('age', 'name'), 'name': <member 'name' of 'B' objects>} '''
使用定義__slots__的類(lèi)的注意事項(xiàng)
class Foo(object): __slots__ = ('age','name')
1.__slots__僅對(duì)當(dāng)前類(lèi)起作用,對(duì)子類(lèi)是不起作用的,除非在子類(lèi)中也定義__slots__,這樣,子類(lèi)允許定義的屬性就是自身的__slots__加上父類(lèi)的__slots__。
class F1(Foo): pass class F2(Foo): __slots__ = () f1,f2 = F1(),F2() f1.a = 1 f2.a = 1 #AttributeError: 'F2' object has no attribute 'a' f2.age = 1
2.如果實(shí)例未給__slots__中的變量賦值,該實(shí)例不能使用__slots__中的變量。
f = Foo() print f.age #AttributeError: age f.age = 1 print f.age #1
3.實(shí)例將不再擁有__dict__,但是類(lèi)還是擁有__dict__屬性的,所以還是可以給類(lèi)增加類(lèi)屬性的;
f = Foo() Foo.xx = 1 print f.xx #1
4.定義了__slots__后,如果__slots__中的變量為類(lèi)變量,該變量對(duì)于該類(lèi)的實(shí)例來(lái)說(shuō)是只讀的。如果想修改的話,可以通過(guò)類(lèi)來(lái)修改。
class Foo(object): __slots__ = ('age','name') age = 10 def __init__(self): self.name = 'xiaoming' f = Foo() print f.name #'xiaoming' print f.age #10 f.name = 'xiaohong' #f.age = 12 #AttributeError: 'Foo' object attribute 'age' is read-only Foo.age = 12 #正確 print f.name #'xiaohong' print f.age #12 #del f.age #AttributeError: 'Foo' object attribute 'age' is read-only #del f.name 調(diào)用的是描述符方法__delete__,應(yīng)該是將描述符中存儲(chǔ)的實(shí)例與值的映射刪除了 del f.name #實(shí)例屬性的刪除還是可以的,但是刪除的并不是類(lèi)字典中的name屬性 print f.name #AttributeError: name del Foo.age #通過(guò)類(lèi)來(lái)刪除類(lèi)屬性還是可以的,不過(guò)這樣會(huì)影響該類(lèi)的所有實(shí)例 print f.age #AttributeError: 'Foo' object has no attribute 'age'
原因不知道…有知道的大神求指導(dǎo)…
參考網(wǎng)址
1.http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/0013868200605560b1bd3c660bf494282ede59fee17e781000
2.http://www.jianshu.com/p/ef1797577f71
3.http://www.jianshu.com/p/82ce2151d73b
4.http://blog.csdn.net/lis_12/article/details/53453665
到此這篇關(guān)于Python __slots__的使用方法的文章就介紹到這了,更多相關(guān)Python __slots__內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python中array數(shù)組添加一行或一列數(shù)據(jù)的具體實(shí)現(xiàn)
這篇文章主要給大家介紹了關(guān)于python中array數(shù)組添加一行或一列數(shù)據(jù)的具體實(shí)現(xiàn),最近經(jīng)常使用到數(shù)組方法,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-09-09Python編程實(shí)現(xiàn)數(shù)學(xué)運(yùn)算求一元二次方程的實(shí)根算法示例
這篇文章主要介紹了Python編程實(shí)現(xiàn)數(shù)學(xué)運(yùn)算求一元二次方程的實(shí)根算法,涉及Python數(shù)學(xué)運(yùn)算求解方程的相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-04-04python中for循環(huán)把字符串或者字典添加到列表的方法
今天小編就為大家分享一篇python中for循環(huán)把字符串或者字典添加到列表的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-07-07pytorch中的model=model.to(device)使用說(shuō)明
這篇文章主要介紹了pytorch中的model=model.to(device)使用說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-05-05Python爬蟲(chóng)eval實(shí)現(xiàn)看漫畫(huà)漫畫(huà)柜mhgui實(shí)戰(zhàn)分析
這篇文章主要為大家介紹了Python爬蟲(chóng)eval實(shí)現(xiàn)看漫畫(huà)漫畫(huà)柜mhgui實(shí)戰(zhàn)分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07在雙python下設(shè)置python3為默認(rèn)的方法
這篇文章主要介紹了如何在雙python下設(shè)置python3為默認(rèn),本文通過(guò)一個(gè)例子分步驟給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-10-10python 利用jieba.analyse進(jìn)行 關(guān)鍵詞提取
這篇文章主要介紹了python 利用jieba.analyse進(jìn)行關(guān)鍵詞提取的方法,幫助大家更好的利用python,感興趣的朋友可以了解下2020-12-12