91aaa在线国内观看,亚洲AV午夜福利精品一区二区,久久偷拍人视频,久久播这里有免费视播

<strong id="fvuar"></strong>

  • <sub id="fvuar"><dl id="fvuar"><em id="fvuar"></em></dl></sub>

    1. 千鋒教育-做有情懷、有良心、有品質(zhì)的職業(yè)教育機構(gòu)

      手機站
      千鋒教育

      千鋒學習站 | 隨時隨地免費學

      千鋒教育

      掃一掃進入千鋒手機站

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

      關(guān)注千鋒學習站小程序
      隨時隨地免費學習課程

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

      Python之詳解__slots__

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

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

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

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

      比如這段代碼:

      classExp:

      def__init__(self):

      self.a=None

      self.b=None

      if__name__=="__main__":

      exp=Exp()

      exp.c=3

      print(exp.c)

      我們定義了一個類叫做Exp,我們?yōu)樗鼊?chuàng)建了a和b兩個成員。但是我們在使用的時候,對c成員進行了賦值。要知道Exp類當中是沒有成員c的,但是程序并不會報錯,我們這么運行了之后它會將c添加進這個實例當中。

      從一方面來看,這當然非常靈活,但是另一方面,這也留下了隱患。如果用戶隨意添加屬性,可能會導致未知的問題,尤其在復雜的系統(tǒng)當中。所以有些時候為了嚴謹,我們會不希望用戶做這種動態(tài)的修改。__slots__正是用來做這個的。

      我們把這個關(guā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)

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

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

      如果了解過Python底層的實現(xiàn)原理,你會發(fā)現(xiàn)在Python當中為每一個實例都創(chuàng)建了一個字典,就是大名鼎鼎的__dict__字典。正是因為背后有一個字典,所以我們才可以創(chuàng)造出原本不存在的成員,也才支持這樣動態(tài)的效果。我們可以人工地調(diào)用這個字典輸出其中的內(nèi)容,我們在加上__slots__關(guān)鍵字之前,輸出的結(jié)果是這樣的:

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

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

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

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

      classExp:

      def__init__(self,param):

      self.param=param

      @property

      defparam(self):

      returnself._param

      @param.setter

      defparam(self,value):

      self._param=value

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

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

      答案很簡單,為了校驗變量類型。

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

      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還有一個用法是代替函數(shù)。舉個例子:

      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)用一個函數(shù),這樣做其實是一種動態(tài)計算。hello的結(jié)果并沒有被存儲起來,之后當我們調(diào)用的時候才會執(zhí)行,在一些場景下這樣做會非常方便。

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

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

      我們來看個簡單的例子:

      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)常還會看到一些兩個下劃線的變量和方法,那么它們之間又有什么區(qū)別呢?

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

      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()

      請問最后會輸出什么?

      我們試一下就知道,第一行輸出的是privateExpB,這個沒有問題。但是后面兩個是什么?

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

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

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

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