本文爲轉載整理,我轉過來做爲備份留做本身查看,請點擊連接閱讀原文。原文連接爲:點此python
Python類與實例的講解,至關通俗易懂。很是推薦!git
class Person:
注意,類的名稱通常用大寫字母開頭,這是慣例。固然,若是故意不遵循此慣例,也何嘗不可,可是,會給別人閱讀乃至於本身之後閱讀帶來麻煩。既然你們都是靠右走的,你就別非要在路中間睡覺了。github
接下來,通常都要編寫構造函數,在寫這個函數以前,先解釋一下什麼是構造函數。golang
class Person: def __init__(self, name, lang, website): self.name = name self.lang = lang self.website = website
上面的類中,首先呈現出來的是一個名爲:init()的函數,注意,這個函數是以兩個下劃線開始,而後是init,最後以兩個下劃線結束。這是一個函數,就跟咱們此前學習過的函數同樣的函數。可是,這個函數又有點奇特,它的命名是用「__」開始和結束。web
請看官在這裏要明確一個基本概念,類就是一種對象類型,和跟前面學習過的數值、字符串、列表等等類型同樣。好比這裏構建的類名字叫作Person,那麼就是咱們要試圖創建一種對象類型,這種類型被稱之爲Person,就如同有一種對象類型是list同樣。函數
在構建Person類的時候,首先要作的就是對這種類型進行初始化,也就是要說明這種類型的基本結構,一旦這個類型的對象被調用了,第一件事情就是要運行這個類型的基本結構,也就是類Person的基本結構。就比如咱們每一個人,在頭腦中都有關於「人」這樣一個對象類型(對應着類),一旦遇到張三(張三是一個具體人),咱們首先運行「人」這個類的基本結構:一個鼻子兩隻眼,鼻子下面一張嘴。若是張三符合這個基本機構,咱們不會感到驚詫(不報錯),若是張三不符合這個基本結構(好比三隻眼睛),咱們就會感到驚詫(報錯了)。學習
因爲類是咱們本身構造的,那麼基本結構也是咱們本身手動構造的。在類中,基本結構是寫在init()這個函數裏面。故這個函數稱爲構造函數,擔負着對類進行初始化的任務。google
仍是回到Person這個類,若是按照上面的代碼,寫好了,是否是init()就運行起來了呢?不是!這時候尚未看到張三呢,必須看到張三才能運行。所謂看到張三,看到張三這樣一個具體的實實在在的人,此動做,在python中有一個術語,叫作實例化。當類Person實例化後馬上運行init()函數。
上面關於類的講解很形象生動!spa
#!/usr/bin/env python #coding:utf-8 class Person: def __init__(self, name, lang, website): self.name = name self.lang = lang self.website = website info = Person("qiwsir","python","qiwsir.github.io") #實例化Person print "info.name=",info.name print "info.lang=",info.lang print "info.website=",info.website #上面代碼的運行結果: info.name= qiwsir info.lang= python info.website= qiwsir.github.io
在上面的代碼中,創建的類Person,構造函數申明瞭這個類的基本結構:name,lang,website。.net
注意觀察:info=Person(「qiwsir」,」python」,」qiwsir.github.io」),這句話就是將類Person實例化了。也就是在內存中建立了一個對象,這個對象的類型是Person類型,這個Person類型是什麼樣子的呢?就是init()所構造的那樣。在實例化時,必須經過參數傳入具體的數據:name=」qiwsir」,lang=」python」,website=」qiwsir.github.io」。這樣在內存中就存在了一個對象,這個對象的類型是Person,而後經過賦值語句,與變量info創建引用關係。請看官回憶之前已經講述過的變量和對象的引用關係。
• 「類提供默認行爲,是實例的工廠」,我以爲這句原話很是經典,一下道破了類和實例的關係。看上面代碼,體會一下,是否是這個理?所謂工廠,就是能夠用同一個模子作出不少具體的產品。類就是那個模子,實例就是具體的產品。因此,實例是程序處理的實際對象。
• 類是由一些語句組成,可是實例,是經過調用類生成,每次調用一個類,就獲得這個類的新的實例。
• 對於類的:class Person,class是一個可執行的語句。若是執行,就獲得了一個類對象,而且將這個類對象賦值給對象名(好比Person)。
細心的看官可能注意到了,在構造函數中,第一個參數是self,可是在實例化的時候,彷佛沒有這個參數什麼事兒,那麼self是幹什麼的呢?
self是一個很神奇的參數。
在Person實例化的過程當中,數據」qiwsir」,」python」,」qiwsir.github.io」經過構造函數(init())的參數已經存入到內存中,而且這些數據以Person類型的面貌存在組成一個對象,這個對象和變量info創建的引用關係。這個過程也可說成這些數據附加到一個實例上。這樣就可以以:object.attribute的形式,在程序中任何地方調用某個數據,例如上面的程序中以info.name獲得」qiwsir」這個數據。這種調用方式,在類和實例中常用,點號「.」後面的稱之爲類或者實例的屬性。
這是在程序中,而且是在類的外面。若是在類的裏面,想在某個地方使用傳入的數據,怎麼辦?
隨着學習的深刻,看官會發現,在類內部,咱們會寫不少不一樣功能的函數,這些函數在類裏面有另一個名稱,曰:方法。那麼,經過類的構造函數中的參數傳入的這些數據也想在各個方法中被使用,就須要在類中長久保存並能隨時調用這些數據。爲了解決這個問題,在類中,全部傳入的數據都賦給一個變量,一般這個變量的名字是self。注意,這是習慣,並且是共識,因此,看官不要另外取別的名字了。
在構造函數中的第一個參數self,就是起到了這個做用——接收實例化過程當中傳入的全部數據,這些數據是經過構造函數後面的參數導入的。顯然,self應該就是一個實例(準確說法是應用實例),由於它所對應的就是具體數據。
若是將上面的類增長兩句,看看效果:
#!/usr/bin/env python #coding:utf-8 class Person: def __init__(self, name, lang, website): self.name = name self.lang = lang self.website = website print self #打印,看看什麼結果 print type(self) #運行結果 <__main__.Person instance at 0xb74a45cc> <type 'instance'>
證明了推理。self就是一個實例(準確說是實例的引用變量)。
self這個實例跟前面說的那個info所引用的實例對象同樣,也有屬性。那麼,接下來就規定其屬性和屬性對應的數據。上面代碼中:self.name = name,就是規定了self實例的一個屬性,這個屬性的名字也叫作name,這個屬性的數據等於構造函數的參數name所導入的數據。注意,self.name中的name和構造函數的參數name沒有任何關係,它們兩個同樣,只不過是一種起巧合(常常巧合),或者說是寫代碼的人懶惰,不想另外取名字而已,無他。固然,若是寫成self.xxxooo = name,也是能夠的。
其實,從效果的角度來理解,可能更簡單一些,那就是類的實例info對應着self,info經過self導入實例屬性的全部數據。
固然,self的屬性數據,也不必定非得是由參數傳入的,也能夠在構造函數中本身設定。好比:
#!/usr/bin/env python #coding:utf-8 class Person: def __init__(self, name, lang, website): self.name = name self.lang = lang self.website = website self.email = "qiwsir@gmail.com" #這個屬性不是經過參數傳入的 info = Person("qiwsir","python","qiwsir.github.io") print "info.name=",info.name print "info.lang=",info.lang print "info.website=",info.website print "info.email=",info.email #info經過self創建實例,並導入實例屬性數據 #運行結果 info.name= qiwsir info.lang= python info.website= qiwsir.github.io info.email= qiwsir@gmail.com #打印結果
經過這個例子,其實讓咱們拓展了對self的認識,也就是它不只僅是爲了在類內部傳遞參數導入的數據,還能在構造函數中,經過self.attribute的方式,規定self實例對象的屬性,這個屬性也是類實例化對象的屬性,即作爲類經過構造函數初始化後所具備的屬性。因此在實例info中,經過info.email一樣可以獲得該屬性的數據。在這裏,就能夠把self形象地理解爲「內外兼修」了。或者按照前面所提到的,將info和self對應起來,self主內,info主外。
其實,self的話題尚未結束,後面的方法中還會出現它。它真的神奇呀。
前面已經說過了,構造函數init就是一個函數,只不過長相有點古怪罷了。那麼,函數中的操做在構造函數中依然可行。好比:
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") #導入一個數據name="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
在這段代碼中,看官首先要體會一下,「類是實例的工廠」這句話的含義,經過類Person生成了兩個實例:laoqi、info
此外,在看函數賦值的狀況,容許設置默認參數值。
至此,僅僅是初步構建了一個類的基本結構,完成了類的初始化。
#coding=utf-8 #定義父類 用於單位轉換 class ScaleConverter: def __init__(self,unit_from,unit_to,factor): #第一個參數必須是self self.unit_from=unit_from self.unit_to=unit_to self.factor=factor def description(self): #函數必須傳入self,self用於區分是哪一個對象調用該方法 return 'Convert '+self.unit_from+' to '+self.unit_to def convert(self,value): return value*self.factor c1=ScaleConverter('inches','mm',25) #實例化類 print(c1.description()) print(str(c1.convert(2))+c1.unit_to) #============================================================================ class ScaleAndOffsetConverter(ScaleConverter): # 定義子類,類繼承 def __init__(self,unit_from,unit_to,factor,offset): ScaleConverter.__init__(self,unit_from,unit_to,factor) #經過父類的init()函數構造 self.offset=offset def convert(self,value): #覆蓋父類的convert()函數 return value*self.factor+self.offset c2=ScaleAndOffsetConverter('C','F',1.8,32) #實例化類 print(c2.description()) print(str(c2.convert(20))+c2.unit_to)