国产睡熟迷奷白丝护士系列精品,中文色字幕网站,免费h网站在线观看的,亚洲开心激情在线

      <sup id="hb9fh"></sup>
          1. 千鋒教育-做有情懷、有良心、有品質(zhì)的職業(yè)教育機(jī)構(gòu)

            手機(jī)站
            千鋒教育

            千鋒學(xué)習(xí)站 | 隨時(shí)隨地免費(fèi)學(xué)

            千鋒教育

            掃一掃進(jìn)入千鋒手機(jī)站

            領(lǐng)取全套視頻
            千鋒教育

            關(guān)注千鋒學(xué)習(xí)站小程序
            隨時(shí)隨地免費(fèi)學(xué)習(xí)課程

            當(dāng)前位置:首頁  >  技術(shù)干貨  > Python之詳解__slots__

            Python之詳解__slots__

            來源:千鋒教育
            發(fā)布人:xqq
            時(shí)間: 2023-11-07 13:51:58 1699336318

            這個(gè)__slots__關(guān)鍵字究竟是做什么的呢?

            它主要有兩個(gè)功能,我們先來說第一個(gè)功能,就是限制用戶的使用。

            我們都知道Python是一門非常靈活的動(dòng)態(tài)語言,很多在其他語言看起來完全不能容忍的事情在Python當(dāng)中是可行的,這也是Python的設(shè)計(jì)理念,為了靈活和代碼方便犧牲了效率。比如我們來看一個(gè)很簡單的例子,由于Python是動(dòng)態(tài)語言,所以類的成員甚至可以在類創(chuàng)建好了之后動(dòng)態(tài)創(chuàng)建。這在靜態(tài)語言當(dāng)中是絕對(duì)不行的,我們只能調(diào)用類當(dāng)中已有的屬性,是不能或者很難添加新屬性的。

            比如這段代碼:

            classExp:

            def__init__(self):

            self.a=None

            self.b=None

            if__name__=="__main__":

            exp=Exp()

            exp.c=3

            print(exp.c)

            我們定義了一個(gè)類叫做Exp,我們?yōu)樗鼊?chuàng)建了a和b兩個(gè)成員。但是我們?cè)谑褂玫臅r(shí)候,對(duì)c成員進(jìn)行了賦值。要知道Exp類當(dāng)中是沒有成員c的,但是程序并不會(huì)報(bào)錯(cuò),我們這么運(yùn)行了之后它會(huì)將c添加進(jìn)這個(gè)實(shí)例當(dāng)中。

            從一方面來看,這當(dāng)然非常靈活,但是另一方面,這也留下了隱患。如果用戶隨意添加屬性,可能會(huì)導(dǎo)致未知的問題,尤其在復(fù)雜的系統(tǒng)當(dāng)中。所以有些時(shí)候?yàn)榱藝?yán)謹(jǐn),我們會(huì)不希望用戶做這種動(dòng)態(tài)的修改。__slots__正是用來做這個(gè)的。

            我們把這個(gè)關(guān)鍵字加上,再來運(yùn)行結(jié)果就不一樣了:

            classExp:

            __slots__=['a','b']

            def__init__(self):

            self.a=None

            self.b=None

            if__name__=="__main__":

            exp=Exp()

            exp.c=3

            print(exp.c)

            如果你運(yùn)行這段代碼的話,你會(huì)得到一個(gè)報(bào)錯(cuò),提示你Exp這個(gè)對(duì)象當(dāng)中并沒有c這個(gè)成員,也就是說我們只能運(yùn)用__slots__這個(gè)關(guān)鍵字當(dāng)中定義的成員,對(duì)于沒有定義的成員不能隨意創(chuàng)建,這樣就限制了用戶的使用。

            雖然現(xiàn)在大部分人使用這個(gè)關(guān)鍵字都是報(bào)著這個(gè)目的,但是很遺憾的是,Python創(chuàng)建者的初衷其實(shí)并不是這個(gè)。這就談到了__slots__關(guān)鍵字的第二個(gè)作用,就是節(jié)省內(nèi)存。

            如果了解過Python底層的實(shí)現(xiàn)原理,你會(huì)發(fā)現(xiàn)在Python當(dāng)中為每一個(gè)實(shí)例都創(chuàng)建了一個(gè)字典,就是大名鼎鼎的__dict__字典。正是因?yàn)楸澈笥幸粋€(gè)字典,所以我們才可以創(chuàng)造出原本不存在的成員,也才支持這樣動(dòng)態(tài)的效果。我們可以人工地調(diào)用這個(gè)字典輸出其中的內(nèi)容,我們?cè)诩由蟔_slots__關(guān)鍵字之前,輸出的結(jié)果是這樣的:

            {'a':None,'b':None}

            但是加上了這個(gè)關(guān)鍵字之后,會(huì)得到一個(gè)報(bào)錯(cuò),會(huì)告訴你Exp這個(gè)對(duì)象當(dāng)中沒有__dict__這個(gè)成員。原因很簡單,因?yàn)槭褂胐ict來維護(hù)實(shí)例,會(huì)消耗大量的內(nèi)存,額外存儲(chǔ)了許多數(shù)據(jù),而使用__slots__之后,Python內(nèi)部將不再為實(shí)例創(chuàng)建一個(gè)字典來維護(hù),而是會(huì)使用一個(gè)固定大小的數(shù)組,這樣就節(jié)省了大量的空間。這個(gè)節(jié)省可不是一點(diǎn)半點(diǎn),一般可以節(jié)省一半以上。也就是說犧牲了一定的靈活性,保證了性能。這一點(diǎn)也是__slots__這個(gè)關(guān)鍵字設(shè)計(jì)的初衷,但是現(xiàn)在很多人都用錯(cuò)了地方。

            property這個(gè)關(guān)鍵字在的文章當(dāng)中曾經(jīng)提到過,不過很不好意思的是,由于之前寫文章的時(shí)候?qū)λ牧私膺€很有限,導(dǎo)致一些闡述存在一些謬誤,所以這里再提一下這個(gè)關(guān)鍵字的運(yùn)用作為彌補(bǔ)。

            property可以幫我們綁定類當(dāng)中一些屬性的賦值和獲取,也就是get和set。我們來看個(gè)例子:

            classExp:

            def__init__(self,param):

            self.param=param

            @property

            defparam(self):

            returnself._param

            @param.setter

            defparam(self,value):

            self._param=value

            這里的property注解會(huì)在我們調(diào)用.param的時(shí)候被執(zhí)行,而param.setter會(huì)在我們?yōu)閜aram這個(gè)屬性賦值的時(shí)候被執(zhí)行。所以你可能會(huì)奇怪,為什么我們?cè)赺_init__方法當(dāng)中初始化的時(shí)候用的是self.param=param而不是self._param=param,這是因?yàn)槲覀冊(cè)趫?zhí)行前者的時(shí)候,Python一樣會(huì)調(diào)用@param.setter這個(gè)注解,所以我們沒有必要寫成后者的形式。當(dāng)然你也可以這么寫,不過兩者是完全等價(jià)的。

            作為一個(gè)前Java程序員為類當(dāng)中所有變量加上get和set方法幾乎成了政治正確,所以我特別喜歡為類當(dāng)中所有的屬性加上property。但是這是不對(duì)的,加上property是非常耗時(shí)的,所以如非必要不要這么做,我們直接調(diào)用來進(jìn)行賦值就好了,如果有必要,我們可以手動(dòng)寫上get和set方法。那么問題來了,既然不是為了規(guī)范,那么我們又為什么要用到property呢?

            答案很簡單,為了校驗(yàn)變量類型。

            由于Python是動(dòng)態(tài)語言,并且是隱式類型的,所以我們拿到變量的時(shí)候并不知道它究竟是什么類型,也不知道用戶為給它賦值成什么類型。所以在一些情況下我們可能會(huì)希望做好限制,告訴用戶只能將這個(gè)變量賦值成這個(gè)類型,否則就會(huì)報(bào)錯(cuò)。通過使用property,我們可以很方便地做到這點(diǎn)。

            classExp:

            def__init__(self,param):

            self.param=param

            @property

            defparam(self):

            returnself._param

            @param.setter

            defparam(self,value):

            ifnotisinstance(value,str):

            raiseTypeError('Wantastring')

            self._param=value

            除此之外,property還有一個(gè)用法是代替函數(shù)。舉個(gè)例子:

            classExp:

            def__init__(self,param):

            self.param=param

            @property

            defparam(self):

            returnself._param

            @param.setter

            defparam(self,value):

            ifnotisinstance(value,str):

            raiseTypeError('Wantastring')

            self._param=value

            @property

            defhello(self):

            return'hello'+self.param

            這樣我們就可以通過.hello來代替調(diào)用一個(gè)函數(shù),這樣做其實(shí)是一種動(dòng)態(tài)計(jì)算。hello的結(jié)果并沒有被存儲(chǔ)起來,之后當(dāng)我們調(diào)用的時(shí)候才會(huì)執(zhí)行,在一些場景下這樣做會(huì)非常方便。

            命名規(guī)范最后我們來看下Python對(duì)象當(dāng)中的命名規(guī)范,在之前的文章當(dāng)中我們?cè)?jīng)說過,在Python當(dāng)中沒有對(duì)public和private的字段做區(qū)分,所有的字段都是public的,也就是說用戶可以拿到類當(dāng)中所有的字段和方法。為了規(guī)范,程序員們約定俗成,決定所有加了下劃線的方法和變量都看成是private的,即使我們能調(diào)用,但是一般情況下我們也不這么干。

            所以我們通常會(huì)寫兩個(gè)方法,一個(gè)是公開的接口,一個(gè)是內(nèi)部的實(shí)現(xiàn)。我們調(diào)用的時(shí)候只調(diào)用公開的接口,公開的接口再去調(diào)用內(nèi)部的實(shí)現(xiàn)。這在Python當(dāng)中已經(jīng)成了慣例,因?yàn)槲覀冊(cè)谡{(diào)用內(nèi)部方法的時(shí)候,往往還會(huì)傳入一些內(nèi)部的參數(shù)。

            我們來看個(gè)簡單的例子:

            classExpA:

            def__init__(self):

            pass

            defpublic_func(self):

            self._private_func()

            def_private_func(self):

            print('privateExpA')

            if__name__=="__main__":

            exp=ExpA()

            exp.public_func()

            除了_之外我們經(jīng)常還會(huì)看到一些兩個(gè)下劃線的變量和方法,那么它們之間又有什么區(qū)別呢?

            為了回答這個(gè)問題,我們來看下面這個(gè)例子:

            classExpA:

            def__init__(self):

            pass

            defpublic_func(self):

            self.__private_func()

            def__private_func(self):

            print('privateExpA')

            classExpB(ExpA):

            def__init__(self):

            pass

            defpublic_func(self):

            self.__private_func()

            def__private_func(self):

            print('privateExpB')

            if__name__=="__main__":

            exp=ExpB()

            exp.public_func()

            exp._ExpB__private_func()

            exp._ExpA__private_func()

            請(qǐng)問最后會(huì)輸出什么?

            我們?cè)囈幌戮椭?,第一行輸出的是privateExpB,這個(gè)沒有問題。但是后面兩個(gè)是什么?

            后面兩個(gè)就是__private_func,只不過系統(tǒng)自動(dòng)將它重新命名了。重新命名的原因也很簡單,因?yàn)镻ython禁止加了兩個(gè)下劃線的方法被子類覆蓋。所以這兩者的區(qū)別就在這里,它們都被認(rèn)為是private的方法和屬性,但是一個(gè)下劃線允許子類覆蓋,而兩個(gè)下劃線不行。所以如果我們?cè)陂_發(fā)的時(shí)候希望我們某一個(gè)方法不會(huì)被子類覆蓋,那么我們就需要加上兩個(gè)下劃線。

            最后,我們來看一個(gè)小問題。在C++當(dāng)中當(dāng)我們的變量名和系統(tǒng)的關(guān)鍵字沖突的時(shí)候,我們往往會(huì)在變量前面加上一個(gè)_來作為區(qū)分。但是由于Python當(dāng)中下劃線被賦予了含義,所以我們不能這么干,那么當(dāng)變量沖突的時(shí)候應(yīng)該怎么辦呢?答案也很簡單,我們可以把下劃線加在后面,比如lambda_。

            以上內(nèi)容為大家介紹了Python之詳解__slots__,希望對(duì)大家有所幫助,如果想要了解更多Python相關(guān)知識(shí),請(qǐng)關(guān)注IT培訓(xùn)機(jī)構(gòu):千鋒教育。

            聲明:本站稿件版權(quán)均屬千鋒教育所有,未經(jīng)許可不得擅自轉(zhuǎn)載。
            10年以上業(yè)內(nèi)強(qiáng)師集結(jié),手把手帶你蛻變精英
            請(qǐng)您保持通訊暢通,專屬學(xué)習(xí)老師24小時(shí)內(nèi)將與您1V1溝通
            免費(fèi)領(lǐng)取
            今日已有369人領(lǐng)取成功
            劉同學(xué) 138****2860 剛剛成功領(lǐng)取
            王同學(xué) 131****2015 剛剛成功領(lǐng)取
            張同學(xué) 133****4652 剛剛成功領(lǐng)取
            李同學(xué) 135****8607 剛剛成功領(lǐng)取
            楊同學(xué) 132****5667 剛剛成功領(lǐng)取
            岳同學(xué) 134****6652 剛剛成功領(lǐng)取
            梁同學(xué) 157****2950 剛剛成功領(lǐng)取
            劉同學(xué) 189****1015 剛剛成功領(lǐng)取
            張同學(xué) 155****4678 剛剛成功領(lǐng)取
            鄒同學(xué) 139****2907 剛剛成功領(lǐng)取
            董同學(xué) 138****2867 剛剛成功領(lǐng)取
            周同學(xué) 136****3602 剛剛成功領(lǐng)取
            相關(guān)推薦HOT