<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                現在開始不用偽代碼了,用真正的python代碼來理解類。當然,例子還是要用讀者感興趣的例子。 ## [](https://github.com/qiwsir/StarterLearningPython/blob/master/207.md#新式類和舊式類)新式類和舊式類 因為python是一個不斷發展的高級語言(似乎別的語言是不斷發展的,甚至于自然語言也是),導致了在python2.x的版本中,有“新式類”和“舊式類(也叫做經典類)”之分。新式類是python2.2引進的,在此后的版本中,我們一般用的都是新式類。本著知其然還要知其所以然的目的,簡單回顧一下兩者的差別。 ~~~ >>> class AA: ... pass ... ~~~ 這是定義了一個非常簡單的類,而且是舊式類。至于如何定義類,下面會詳細說明。讀者姑且囫圇吞棗似的的認同我剛才建立的名為`AA`的類,為了簡單,這個類內部什么也不做,就是用`pass`一帶而過。但不管怎樣,是一個類,而且是一個舊式類(或曰經典類) 然后,將這個類實例化(還記得上節中實例化嗎?對,就是那個王美女干的事情): ~~~ >>> aa = AA() ~~~ 不要忘記,實例化的時候,類的名稱后面有一對括號。接下來做如下操作: ~~~ >>> type(AA) <type 'classobj'> >>> aa.__class__ <class __main__.AA at 0xb71f017c> >>> type(aa) <type 'instance'> ~~~ 解讀一下上面含義: * `type(AA)`:查看類`AA`的類型,返回的是`'classobj'` * `aa.__class__`:aa是一個實例,也是一個對象,每個對象都有`__class__`屬性,用于顯示它的類型。這里返回的結果是`<class __main__.AA at 0xb71f017c>`,從這個結果中可以讀出的信息是,aa是類AA的實例,并且類AA在內存中的地址是`0xb71f017c`。 * `type(aa)`:是要看實例aa的類型,它顯示的結果是`'instance`,意思是告訴我們它的類型是一個實例。 在這里是不是有點感覺不和諧呢?`aa.__class__`和`type(aa)`都可以查看對象類型,但是它們居然顯示不一樣的結果。比如,查看這個對象: ~~~ >>> a = 7 >>> a.__class__ <type 'int'> >>> type(a) <type 'int'> ~~~ 別忘記了,前面提到過的“萬物皆對象”,那么一個整數7也是對象,用兩種方式查看,返回的結果一樣。為什么到類(嚴格講是舊式類)這里,居然返回不一樣呢?太不和諧了。 于是乎,就有了新式類,從python2.2開始,變成這樣了: ~~~ >>> class BB(object): ... pass ... >>> bb = BB() >>> bb.__class__ <class '__main__.BB'> >>> type(bb) <class '__main__.BB'> ~~~ 終于把兩者統一起來了,世界和諧了。 這就是新式類和舊式類的不同。 當然,不同點絕非僅僅于此,這里只不過提到一個現在能夠理解的不同罷了。另外的不同還在于兩者對于多重繼承的查找和調用方法不同,舊式類是深度優先,新式類是廣度優先。可以先不理解,后面會碰到的。 不管是新式類、還是舊式類,都可以通過這樣的方法查看它們在內存中的存儲空間信息 ~~~ >>> print aa <__main__.AA instance at 0xb71efd4c> >>> print bb <__main__.BB object at 0xb71efe6c> ~~~ 分別告訴了我們兩個實例是基于誰生成的,不過還是稍有區別。 知道了舊式類和新式類,那么下面的所有內容,就都是對新式類而言。“喜新厭舊”不是編程經常干的事情嗎?所以,舊式類就不是我們討論的內容了。 還要注意,如果你用的是python3,就不用為新式類和舊式類而擔心了,因為在python3中壓根兒就沒有這個問題存在。 如何定義新式類呢? 第一種定義方法,就是如同前面那樣: ~~~ >>> class BB(object): ... pass ... ~~~ 跟舊式類的區別就在于類的名字后面跟上`(object)`,這其實是一種名為“繼承”的類的操作,當前的類BB是以類object為上級的(object被稱為父類),即BB是繼承自類object的新類。在python3中,所有的類自然地都是類object的子類,就不用彰顯出繼承關系了。對了,這里說的有點讓讀者糊涂,因為冒出來了“繼承”、“父類”、“子類”,不用著急,繼續向下看。下面精彩,并且能解惑。 第二種定義方法,在類的前面寫上這么一句:`__metaclass__ == type`,然后定義類的時候,就不需要在名字后面寫`(object)`了。 ~~~ >>> __metaclass__ = type >>> class CC: ... pass ... >>> cc = CC() >>> cc.__class__ <class '__main__.CC'> >>> type(cc) <class '__main__.CC'> ~~~ 兩種方法,任你選用,沒有優劣之分。 ## [](https://github.com/qiwsir/StarterLearningPython/blob/master/207.md#創建類)創建類 因為在一般情況下,一個類都不是兩三行能搞定的。所以,下面可能很少使用交互模式了,因為那樣一旦有一點錯誤,就前功盡棄。我改用編輯界面。你用什么工具編輯?python自帶一個IDE,可以使用。我習慣用vim。你用你習慣的工具即可。如果你沒有別的工具,就用安裝python是自帶的那個IDE。 ~~~ #!/usr/bin/env python # coding=utf-8 __metaclass__ = type class Person: def __init__(self, name): self.name = name def getName(self): return self.name def color(self, color): print "%s is %s" % (self.name, color) ~~~ 上面定義的是一個比較常見的類,一般情況下,都是這樣子的。下面對這個“大眾臉”的類一一解釋。 ### [](https://github.com/qiwsir/StarterLearningPython/blob/master/207.md#新式類)新式類 `__metaclass__ = type`,意味著下面的類是新式類。 ### [](https://github.com/qiwsir/StarterLearningPython/blob/master/207.md#定義類)定義類 `class Person`,這是在聲明創建一個名為"Person"的類。類的名稱一般用大寫字母開頭,這是慣例。如果名稱是兩個單詞,那么兩個單詞的首字母都要大寫,例如`class HotPerson`,這種命名方法有一個形象的名字,叫做“駝峰式命名”。當然,如果故意不遵循此慣例,也未嘗不可,但是,會給別人閱讀乃至于自己以后閱讀帶來麻煩,不要忘記“代碼通常是給人看的,只是偶爾讓機器執行”。既然大家都是靠右走的,你就別非要在路中間睡覺了。 接下來,分別以縮進表示的,就是這個類的內容了。其實那些東西看起來并不陌生,你一眼就認出它們了——就是已經學習過的函數。沒錯,它們就是函數。不過,很多程序員喜歡把類里面的函數叫做“方法”。是的,就是上節中說到的對象的“方法”。我也看到有人撰文專門分析了“方法”和“函數”的區別。但是,我倒是認為這不重要,重要的是類的中所謂“方法”和前面的函數,在數學角度看,絲毫沒有區別。所以,你盡可以稱之為函數。當然,聽到有人說方法,也不要詫異和糊涂。它們本質是一樣的。 需要再次提醒,函數的命名方法是以`def`發起,并且函數名稱首字母不要用大寫,可以使用`aa_bb`的樣式,也可以使用`aaBb`的樣式,一切看你的習慣了。 不過,要注意的是,類中的函數(方法)的參數跟以往的參數樣式有區別,那就是每個函數必須包括`self`參數,并且作為默認的第一個參數。這是需要注意的地方。至于它的用途,繼續學習即可知道。 ### [](https://github.com/qiwsir/StarterLearningPython/blob/master/207.md#初始化)初始化 `def __init__`,這個函數是一個比較特殊的,并且有一個名字,叫做**初始化函數**(注意,很多教材和資料中,把它叫做構造函數,這種說法貌似沒有錯誤,但是一來從字面意義上看,它對應的含義是初始化,二來在python中它的作用和其它語言比如java中的構造函數還不完全一樣,因為還有一個`__new__`的函數,是真正地構造。所以,在本教程中,我稱之為初始化函數)。它是以兩個下劃線開始,然后是init,最后以兩個下劃線結束。 > 所謂初始化,就是讓類有一個基本的面貌,而不是空空如也。做很多事情,都要初始化,讓事情有一個具體的起點狀態。比如你要喝水,必須先初始化杯子里面有水。在python的類中,初始化就擔負著類似的工作。這個工作是在類被實例化的時候就執行這個函數,從而將初始化的一些屬性可以放到這個函數里面。 此例子中的初始化函數,就意味著實例化的時候,要給參數name提供一個值,作為類初始化的內容。通俗點啰嗦點說,就是在這個類被實例化的同時,要通過name參數傳一個值,這個值被一開始就寫入了類和實例中,成為了類和實例的一個屬性。比如: ~~~ girl = Person('canglaoshi') ~~~ girl是一個實例對象,就如同前面所說的一樣,它有屬性和方法。這里僅說屬性吧。當通過上面的方式實例化后,就自動執行了初始化函數,讓實例girl就具有了name屬性。 ~~~ print girl.name ~~~ 執行這句話的結果是打印出`canglaoshi`。 這就是初始化的功能。簡而言之,通過初始化函數,確定了這個實例(類)的“基本屬性”(實例是什么樣子的)。比如上面的實例化之后,就確立了實例girl的name是"canglaoshi"。 初始化函數,就是一個函數,所以,它的參數設置,也符合前面學過的函數參數設置規范。比如 ~~~ def __init__(self,*args): pass ~~~ 這種類型的參數:*args和前面講述函數參數一樣,就不多說了。忘了的看官,請去復習。但是,self這個參數是必須的。 很多時候,并不是每次都要從外面傳入數據,有時候會把初始化函數的某些參數設置默認值,如果沒有新的數據傳入,就應用這些默認值。比如: ~~~ class Person: def __init__(self, name, lang="golang", website="www.google.com"): self.name = name self.lang = lang self.website = website self.email = "qiwsir@gmail.com" laoqi = Person("LaoQi") info = Person("qiwsir",lang="python",website="qiwsir.github.io") print "laoqi.name=",laoqi.name print "info.name=",info.name print "-------" print "laoqi.lang=",laoqi.lang print "info.lang=",info.lang print "-------" print "laoqi.website=",laoqi.website print "info.website=",info.website #運行結果 laoqi.name= LaoQi info.name= qiwsir ------- laoqi.lang= golang info.lang= python ------- laoqi.website= www.google.com info.website= qiwsir.github.io ~~~ 在編程界,有這樣一句話,說“類是實例工廠”,什么意思呢?工廠是干什么的?生產物品,比如生產電腦。一個工廠可以生產好多電腦。那么,類,就能“生產”好多實例,所以,它是“工廠”。比如上面例子中,就有兩個實例。 ### [](https://github.com/qiwsir/StarterLearningPython/blob/master/207.md#函數方法)函數(方法) 還是回到本節開頭的那個類。構造函數下面的兩個函數:`def getName(self)`,`def color(self, color)`,這兩個函數和前面的初始化函數有共同的地方,即都是以self作為第一個參數。 ~~~ def getName(self): return self.name ~~~ 這個函數中的作用就是返回在初始化時得到的值。 ~~~ girl = Person('canglaoshi') name = girl.getName() ~~~ `girl.getName()`就是調用實例girl的方法。調用該方法的時候特別注意,方法名后面的括號不可少,并且括號中不要寫參數,在類中的`getName(self)`函數第一個參數self是默認的,當類實例化之后,調用此函數的時候,第一個參數不需要賦值。那么,變量name的最終結果就是`name = "canglaoshi"`。 同樣道理,對于方法: ~~~ def color(self, color): print "%s is %s" % (self.name, color) ~~~ 也是在實例化之后調用: ~~~ girl.color("white") ~~~ 這也是在執行實例化方法,只是由于類中的該方法有兩個參數,除了默認的self之外,還有一個color,所以,在調用這個方法的時候,要為后面那個參數傳值了。 至此,已經將這個典型的類和調用方法分解完畢,把全部代碼完整貼出,請讀者在從頭到尾看看,是否理解了每個部分的含義: ~~~ #!/usr/bin/env python # coding=utf-8 __metaclass__ = type #新式類 class Person: #創建類 def __init__(self, name): #構造函數 self.name = name def getName(self): #類中的方法(函數) return self.name def color(self, color): print "%s is %s" % (self.name, color) girl = Person('canglaoshi') #實例化 name = girl.getName() #調用方法(函數) print "the person's name is: ", name girl.color("white") #調用方法(函數) print "------" print girl.name #實例的屬性 ~~~ 保存后,運行得到如下結果: ~~~ $ python 20701.py the person's name is: canglaoshi canglaoshi is white ------ canglaoshi ~~~ ### [](https://github.com/qiwsir/StarterLearningPython/blob/master/207.md#類和實例)類和實例 有必要總結一下類和實例的關系: * “類提供默認行為,是實例的工廠”(源自Learning Python),這句話非常經典,一下道破了類和實例的關系。所謂工廠,就是可以用同一個模子做出很多具體的產品。類就是那個模子,實例就是具體的產品。所以,實例是程序處理的實際對象。 * 類是由一些語句組成,但是實例,是通過調用類生成,每次調用一個類,就得到這個類的新的實例。 * 對于類的:`class Person`,class是一個可執行的語句。如果執行,就得到了一個類對象,并且將這個類對象賦值給對象名(比如Person)。 也許上述比較還不足以讓看官理解類和實例,沒關系,繼續學習,在前進中排除疑惑。 ## [](https://github.com/qiwsir/StarterLearningPython/blob/master/207.md#self的作用)self的作用 類里面的函數,第一個參數是self,但是在實例化的時候,似乎沒有這個參數什么事兒,那么self是干什么的呢? self是一個很神奇的參數。 在Person實例化的過程中`girl = Person("canglaoshi")`,字符串"canglaoshi"通過初始化函數(`__init__()`)的參數已經存入到內存中,并且以Person類型的面貌存在,組成了一個對象,這個對象和變量girl建立引用關系。這個過程也可說成這些數據附加到一個實例上。這樣就能夠以:`object.attribute`的形式,在程序中任何地方調用某個數據,例如上面的程序中以`girl.name`的方式得到`"canglaoshi"`。這種調用方式,在類和實例中經常使用,點號“.”后面的稱之為類或者實例的屬性。 這是在程序中,并且是在類的外面。如果在類的里面,想在某個地方使用實例化所傳入的數據("canglaoshi"),怎么辦? 在類內部,就是將所有傳入的數據都賦給一個變量,通常這個變量的名字是self。注意,這是習慣,而且是共識,所以,看官不要另外取別的名字了。 在初始化函數中的第一個參數self,就是起到了這個作用——接收實例化過程中傳入的所有數據,這些數據是初始化函數后面的參數導入的。顯然,self應該就是一個實例(準確說法是應用實例),因為它所對應的就是具體數據。 如果將上面的類稍加修改,看看效果: ~~~ #!/usr/bin/env python # coding=utf-8 __metaclass__ = type class Person: def __init__(self, name): self.name = name print self #新增 print type(self) #新增 ~~~ 其它部分省略。當初始化的時候,就首先要運行構造函數,同時就打印新增的兩條。結果是: ~~~ <__main__.Person object at 0xb7282cec> <class '__main__.Person'> ~~~ 證實了推理。self就是一個實例(準確說是實例的引用變量)。 self這個實例跟前面說的那個girl所引用的實例對象一樣,也有屬性。那么,接下來就規定其屬性和屬性對應的數據。上面代碼中: ~~~ self.name = name ~~~ 就是規定了self實例的一個屬性,這個屬性的名字也叫做name,這個屬性的值等于初始化函數的參數name所導入的數據。注意,`self.name`中的name和初始化函數的參數`name`沒有任何關系,它們兩個一樣,只不過是一種起巧合(經常巧合,其實是為了省事和以后識別方便,故意讓它們巧合。),或者說是寫代碼的人懶惰,不想另外取名字而已,無他。當然,如果寫成`self.xxxooo = name`,也是可以的。 其實,從效果的角度來理解,這么理解更簡化:類的實例girl對應著self,girl通過self導入實例屬性的所有數據。 當然,self的屬性數據,也不一定非得是由參數傳入的,也可以在構造函數中自己設定。比如: ~~~ #!/usr/bin/env python #coding:utf-8 __metaclass__ = type class Person: def __init__(self, name): self.name = name self.email = "qiwsir@gmail.com" #這個屬性不是通過參數傳入的 info = Person("qiwsir") #換個字符串和實例化變量 print "info.name=",info.name print "info.email=",info.email #info通過self建立實例,并導入實例屬性數據 ~~~ 運行結果 ~~~ info.name= qiwsir info.email= qiwsir@gmail.com #打印結果 ~~~ 通過這個例子,其實讓我們拓展了對self的認識,也就是它不僅僅是為了在類內部傳遞參數導入的數據,還能在初始化函數中,通過`self.attribute`的方式,規定self實例對象的屬性,這個屬性也是類實例化對象的屬性,即做為類通過初始化函數初始化后所具有的屬性。所以在實例info中,通過info.email同樣能夠得到該屬性的數據。在這里,就可以把self形象地理解為“內外兼修”了。或者按照前面所提到的,將info和self對應起來,self主內,info主外。 怎么樣?在"canglaoshi"的陪伴下,是不是明白了類的奧妙?
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看