歡迎加入Linux_Python學習羣python
羣號:478616847linux
目錄:git
面向對象的程序設計github
類和對象web
封裝編程
繼承與派生設計模式
多態與多態性安全
靜態方法與類方法服務器
在Python中你們必定聽過一句話,叫作一切皆對象,字典、序列、數字和字符串都是根據類來建立的,在python中面向對象(object)編程是python的ide
核心概念,類(class)最終解釋了面向對象編程思想(OOP),一樣類也是一種對象,它是經過python中的元類(type)建立的,在這個元類中,定義了類
是如何建立的(第七章講解元類),下面開始學習面向對象的編程。
爲何要有面向對象的程序設計?
在學習面向對象以前,咱們要肯定面向對象的程序設計不是編程,而是設計方法和編程思路,就像咱們搭建一個集羣,首先要先設計一下,這個服務器
安裝什麼,那個服務器安裝什麼,面向對象的編程也是同樣的要先設計程序,而後才能進行編程,咱們所寫的程序都是面向過程的,也就說程序是按照
必定的步驟去解決問題,就比如一條流水線,到了哪一個階段該作什麼事,那麼這樣的優勢就是極大地下降了程序的複雜度,缺點就是過程式編程是爲了
解決一個問題的,就比如生成自行車的流水線生產不了汽車,面向過程的編程,每每系統會更加穩定,可是面對頻繁的需求變動的時候,面向過程就變
得乏力,常常的出現改一個地方,其它地方也須要修改。
而面向對象的程序設計核心就是對象,在現實世界中人們的主觀上,將實物分紅不一樣的類型,好比動物中有貓類,狗類等等,而且狗也有不一樣的類型
(好比哈士奇,藏獒),每一個個體也有獨特的屬性(好比體重,毛髮的顏色),因此中把這種形式引進到編程,面向對象的編程首先要把本身當成上帝,
當成創造者,咱們建立一個類以前須要考慮這個類有什麼共同性,有什麼差別性,咱們能夠把這些共同性變成一個類,而後經過這個共同性的類,創
造出差別性的個體。
面向對象的程序設計並非所有。對於一個軟件質量來講,面向對象的程序設計只是用來解決擴展性,而且面向對象編程的可控性差,常常能夠看到
遊戲中的BUG,好比一刀幾千血啊之類的。
1.性能(Performance)是指系統的響應能力,即要通過多長時間才能對某個事件做出響應,或者在某段時間內系統所能處理的事件個數; 2.可用性(Availability)是指系統可以正常運行的時間比例; 3.可靠性(Reliability)是指系統在應用或者錯誤面前,在乎外或者錯誤使用的狀況下維持軟件系統功能特性的能力; 4.健壯性(Robustness)是指在處理或者環境中系統可以承受的壓力或者變動能力; 5.安全性(Security)是指系統向合法用戶提供服務的同事可以阻止非受權用戶使用的企圖或者拒絕服務的能力; 6.可修改性(Modification)是指可以快速地以較高的性能價格比對系統進行變動的能力; 7.可變性(Changeability)是指體系結構擴充或者變動成爲新體系結構的能力; 8.易用性(Usability)是衡量用戶使用軟件產品完成指定任務的難易程度; 9.可測試性(Testability)是指軟件發現故障並隔離定位其故障的能力特性,以及在必定的時間或者成本前提下進行測試設計、測試執行能力; 10.功能性(Function ability)是指系統所能完成所指望工做的能力; 11.互操做性(Inter-Operation)是指系統與外界或系統與系統之間的相互做用能力。 軟件的質量屬性
在python中聲明函數與聲明類很類似,下面開始來建立第一個類
語法:class 類名:
類的註釋
類體
1 class Role: 2 pass
嗯是的只須要這樣就建立完成了一個類,固然這樣建立時毫無心義的,我是用這個引出別的知識點
首先:規範當中規定了類名首字母必須大寫
其次:在python2當中類分爲新式類和經典類,python3中都是新市類,python2中新式類須要讓類繼承object這個父類,而且你們在使用類中
儘可能都用新式類,由於新式類中,新增長了一些屬性,dir()也變得更健壯。
1 #python2中的新式類 2 class Role(object): 3 pass 4 #python2中的經典類 5 class Role(): 6 pass
屬性與實例化
類的做用有兩種,分別是屬性的引用和實例化
類屬性的操做用 (類名.變量名),類的屬性分別數據屬性和函數屬性(也叫方法屬性)
1 class Role: 2 region = "China" 3 def output_region(self): 4 print("My region is China") 5 6 #引用類的數據屬性,該屬性是被全部對象和實例共享的 7 print(Role.region) 8 #經過類引用類的函數屬性 9 Role().output_region() 10 #增長類的數據屬性 11 Role.name = "Hello" 12 #引用新增長的數據屬性 13 print(Role.name) 14 #刪除類中的數據屬性,注意刪除後全部對象和實例都沒法調用 15 del Role.name
實例化
咱們說類最終要生成一個對象的,那麼類生成對象的過程就是實例化,實例化後的對象,能夠操做類中的方法,也能夠傳入本身獨有的屬性,這樣生成的
對象每一個都是個體每一個都是獨立的,以英雄聯盟這個遊戲爲例,咱們建立一個英雄的類,每一個玩家操做的英雄都有本身的獨有屬性例如名字,攻擊力和生
命值,而且每一個英雄都會普通攻擊,並且英雄都有陣營,好比德瑪西亞,諾克薩斯,這些陣營是不變的並且每一個英雄都有,下面模擬實現上述的需求。
1 class Galen: 2 camp = "Demacia" 3 def __init__(self,name,attack,life): 4 self.name = name 5 self.attack = attack 6 self.life = life 7 def slogan(self): 8 print("%s喊了口號:德瑪西亞!"%self.name) 9 10 class Annie: 11 camp = "Noxus" 12 def __init__(self,name,attack,life): 13 self.name = name 14 self.attack = attack 15 self.life = life 16 def slogan(self): 17 print("%s喊了口號:你是個人小熊麼?"%self.name) 18 19 #實例化一個蓋倫 20 G1 = Galen("蓋倫",20,100) 21 #實例化一個安妮 22 A1 = Annie("安妮",17,100) 23 24 G1.slogan() 25 A1.slogan()
首先建立了兩個角色,一個是蓋倫,一個是安妮,其次它們都有陣營,這個陣營不變的,因此用類的數據屬性來定義陣營,而後每一個角色都有本身的屬性
因此用 __init__ 來進行封裝,最後給這兩個英雄都有一個功能,就是喊口號,而且實例化了兩個角色,並且調用了角色中的喊口號的功能。
首先看__init__(構造函數):
好的上面的代碼中提到了實例化,那麼實例化就是 對象名 = 類名(參數),參數無關緊要,可是咱們發現 class Galen:並無要傳入參數啊
反而__init__中有參數,沒錯當實例化的時候,實例化的過程當中就是執行了__init__函數,這個實例化的過程是元類定義的(下章演示)因此
當實例化 A1 = Annie("安妮",17,100) 實際上就是把參數傳給了__init__函數,
可是,看__init__函數是位置參數,咱們說位置參數是必傳的,那麼self是什麼?,而且爲何能在方法 slogan中調用name呢?
self
在實例化的過程中會把實例自己傳給init函數的第一個值
當咱們調用實例的數據屬性的時候是要 A1.name,那麼函數slogan想要調用,實例的數據屬性是不會就要把實例傳入這個函數中,而後
經過傳入的實例去調用實例的數據屬性。就像下面的例子中把slogan函數拿了出來,而後把實例傳入,這樣才能調用name屬性,因此self
就是替咱們作了把實例傳入到函數的操做。
1 class Annie: 2 camp = "Noxus" 3 def __init__(self,name,attack,life): 4 self.name = name 5 self.attack = attack 6 self.life = life 7 8 def slogan(func): 9 print(func.name) 10 11 A1 = Annie("安妮",17,100) 12 slogan(A1)
屬性引用
對於一個實例來講,只有一種功能就是:屬性引用,上面提到的類中有數據屬性和函數屬性,包括__init__也是函數屬性,而且對象/實例
自己只有數據屬性,有人說不對啊實例能夠引用類的函數屬性啊,其實原理是這樣的,原本對實例是沒法使用函數屬性的,可是python的
class機制會將類的函數綁定到對象上,稱爲對象的方法,或者叫綁定方法,下面例子中就能夠清楚的看到 A1.slogan,是綁定到Annie.slogan
上的。
1 class Annie: 2 camp = "Noxus" 3 def __init__(self,name,attack,life): 4 self.name = name 5 self.attack = attack 6 self.life = life 7 8 def slogan(func): 9 print(func.name) 10 11 A1 = Annie("安妮",17,100) 12 print(Annie.slogan) 13 print(A1.slogan) 14 15 """ 16 輸出結果 17 <function Annie.slogan at 0x0060DA08> 18 <bound method Annie.slogan of <__main__.Annie object at 0x00B112D0>> 19 """
對象之間的交互
能夠經過把對象傳給函數來進行對象之間的交互,下面例子中增長了attacks方法,而且這個方法接收一個值,這個值但是是對象,因此把
被攻擊的對象傳入進去,而後讓被攻擊對象的生命值減去攻擊對象的攻擊力,就完成了一次對象之間的交互
1 class Galen: 2 camp = "Demacia" 3 def __init__(self,name,attack,life): 4 self.name = name 5 self.attack = attack 6 self.life = life 7 def slogan(self): 8 print("%s喊了口號:德瑪西亞!"%self.name) 9 10 def attacks(self,enemy): 11 enemy.life-=self.attack 12 13 class Annie: 14 camp = "Noxus" 15 def __init__(self,name,attack,life): 16 self.name = name 17 self.attack = attack 18 self.life = life 19 def slogan(self): 20 print("%s喊了口號:你是個人小熊麼?"%self.name) 21 22 def attacks(self,enemy): 23 enemy.life-=self.attack 24 25 #實例化一個蓋倫 26 G1 = Galen("蓋倫",20,100) 27 #實例化一個安妮 28 A1 = Annie("安妮",17,100) #Annie.__init__(A1,"安妮",17,100) 29 30 #蓋倫攻擊安妮 31 G1.slogan() 32 G1.attacks(A1) 33 print(A1.life) 34 #安妮攻擊蓋倫 35 A1.slogan() 36 A1.attacks(G1) 37 print(G1.life)
類的屬性
就像列表字典同樣,類也有一些方法,一些屬性,有些默認的方法來自type這個元類中,而且咱們在類中定義的數據屬性和方法屬性也會
保存到 類名.__dict__中。這裏面是個字典,有着對於的關係。
1 class Galen: 2 """ 3 這是蓋倫的類 4 """ 5 camp = "Demacia" 6 def __init__(self,name,attack,life): 7 self.name = name 8 self.attack = attack 9 self.life = life 10 def slogan(self): 11 """ 12 喊口號的方法 13 :return:空 14 """ 15 print("%s喊了口號:德瑪西亞!"%self.name) 16 17 def attacks(self,enemy): 18 enemy.life-=self.attack 19 20 print(Galen.__dict__) 21 print(Galen.__name__)#類名 22 print(Galen.__doc__)# 類的文檔字符串 23 print(Galen.__base__)# 類的第一個父類(繼承時會講) 24 print(Galen.__bases__)# 類全部父類構成的元組(繼承時會講) 25 print(Galen.__dict__)# 類的字典屬性 26 print(Galen.__module__)# 類定義所在的模塊 27 print(Galen.__class__)# 實例對應的類(僅新式類中)
類與實例(對象)的名稱空間
建立一個類就會建立一個類的名稱空間,用來存儲類中定義的全部名字,這些名字稱爲類的屬性,而類有兩種屬性:數據屬性和函數屬性
其中類的數據屬性是共享給全部對象的,而類的函數屬性是綁定到全部對象的,能夠看到,下面的代碼中看到,屬性ID是同樣的,函數屬性
的ID是不同的。
class Galen: """ 這是蓋倫的類 """ camp = "Demacia" def __init__(self,name,attack,life): self.name = name self.attack = attack self.life = life def slogan(self): """ 喊口號的方法 :return:空 """ print("%s喊了口號:德瑪西亞!"%self.name) G1 = Galen("蓋倫",20,100) #類的數據屬性 print(id(Galen.camp)) print(id(G1.camp)) #類的數據屬性 print(id(Galen.slogan)) print(id(G1.slogan))
建立一個對象/實例就會建立一個對象/實例的名稱空間,存放對象/實例的名字,稱爲對象/實例的屬性
實例要找到camp,首先會在對象本身的名稱空間找,找不到則去類中找,類也找不到就找父類...最後都找不到就拋出異常
封裝從字面意義上理解的是把東西封起來,在類中要把封裝看的更加抽象,封裝具體分爲數據封裝和方法封裝,就像上面的例子同樣,
假如安妮要刺殺蓋倫,那能讓蓋倫看到安妮的陣營麼?答案是確定不行的,因此封裝不只僅是隱藏,就好比說,百度地圖,提供給我
們一個接口,讓咱們調用百度地圖的定位功能,那麼咱們須要關係百度地圖是怎麼實現定位的麼?確定是不須要。
因此!封裝數據 是爲了保護隱私 封裝方法 隔離複雜度
封裝分爲兩個層面
一、就是上面講到的名稱空間
二、就是用下劃線的命名方式把屬性隱藏起來
封裝數據
數據封裝在下面例子中能夠看出,首先把 Galen的數據屬性camp封裝起來,因此print(Galen.__camp)是調用不到的,而後name屬性也
封裝了起來,那麼經過print(G1.__money)也是訪問不到的,可是在類的內部是能夠調用money屬性的,因此用inquire_mouney來輸出
蓋倫有多少錢,那麼對於用戶來講,調用這個方法就能夠獲得錢,因此用戶不須要關係這個錢是怎麼來的,這個錢是否要進行大量的運算,
也不會知道這個錢是對象的數據屬性,對於用戶來講只知道用這個接口就能夠獲得錢。
1 #!/usr/bin/env python 2 3 class Galen: 4 __camp = "Demacia" 5 print(__camp) 6 7 def __init__(self,name,money): 8 self.name = name 9 self.__money = money 10 11 def inquire_mouney(self): 12 print(self.__money) 13 14 G1 = Galen("蓋倫",1000) 15 16 print(G1.name) 17 G1.inquire_mouney() 18 19 #這樣確定是訪問不到的 20 #print(Galen.__camp) 21 #print(G1.__money)
方法封裝
在方法封裝中咱們把__conversion_mouney方法封裝了起來,它是把人民幣換算成韓元,咱們發如今外面也是調用不到這個方法的,可是
類的內部是能夠調用的。
#!/usr/bin/env python class Galen: __camp = "Demacia" print(__camp) def __init__(self,name,money): self.name = name self.__money = money def __conversion_mouney(self): self.__money = self.__money*163 def inquire_mouney(self): self.__conversion_mouney() print(self.__money,"韓元") G1 = Galen("蓋倫",1000) G1.inquire_mouney() #這樣確定是訪問不到的 # print(Galen.__conversion_mouney) # print(G1.__conversion_mouney)
封裝剖析
封裝,在python中其實就是把被封裝的對象作了一個變形,把對象的數據屬性 __money 變成了 _Galen__money ,把函數方法
__conversion_mouney變成了_Galen__conversion_mouney,把類的數據屬性__camp變成了_Galen__camp,因此正常的去調用
被封裝的屬性和方法是沒法調用的,可使用變形後的名稱調用,固然這種調用方法知道就行了,不要這麼用!
還有這種變形的操做只在函數定義的時候會變形,你之後添加 __xxx 是不會變形的!
1 #!/usr/bin/env python 2 3 class Galen: 4 __camp = "Demacia" 5 def __init__(self,name,money): 6 self.name = name 7 self.__money = money 8 9 def __conversion_mouney(self): 10 self.__money = self.__money*163 11 12 def inquire_mouney(self): 13 self.__conversion_mouney() 14 print(self.__money,"韓元") 15 16 G1 = Galen("蓋倫",1000) 17 18 print(G1._Galen__money) 19 print(Galen._Galen__camp) 20 21 print(Galen.__dict__) 22 print(G1.__dict__)
繼承,從字面上理解就是誰繼承誰,就像linux中的目錄權限同樣,子目錄繼承了父目錄的目錄權限,因此繼承是描述了基類的屬性如何
「遺傳」給派生類。一個子類能夠繼承它的基類的任何屬性,無論是數據屬性仍是方法。好比二哈是哈士奇類,泰迪是泰迪類,它們都是狗
類,那麼狗是狗類,豬是豬類,咱們上升一個高度來看它們都屬於動物類,因此繼承中的父類(也叫基類)有的是不一樣子類共有的屬性和
方法,好比豬與狗都會吃喝拉撒。
繼承的語法:很簡單class 子類名稱(父類名稱) ,而且能夠經過子類實例化的對象來調用父類的方法與屬性,因此繼承的最大的好處就是子類
繼承了父類的所有功能
1 #!/usr/bin/env python 2 3 class Demacia: 4 def monthly_pay(self): 5 print("個人月薪是10000元") 6 7 class Galen(Demacia): 8 def slogan(self): 9 print("德瑪西亞!") 10 11 G1 = Galen() 12 13 G1.slogan() 14 G1.monthly_pay()
提示:若是沒有指定基類,python的類會默認繼承object類,object是全部python類的基類,它提供了一些常見方法(如__str__)的實現。
Super
在上面的例子中父類並無構造函數,有興趣的小夥伴能夠試試,若是在父類加入了構造函數後,再次運行就會報錯,因此在初始化的時候子類
的構造方法必須調用父類的構造方法,來讓父類完成初始化的操做。
1 class Demacia: 2 def __init__(self,salary): 3 self.salary = salary 4 def monthly_pay(self): 5 print("個人月薪是%s元"%self.salary) 6 7 class Galen(Demacia): 8 def __init__(self,name,salary): 9 #增長這麼一行,或者 Demacia.__init__(self,salary) 10 super(Galen,self).__init__(salary) 11 self.name = name 12 13 def slogan(self): 14 print("%s喊了一聲:德瑪西亞!"%self.name) 15 16 G1 = Galen("蓋倫",10000) 17 18 G1.slogan() 19 G1.monthly_pay()
繼承實現的原理(繼承順序)
若是一個類,繼承了多個類,而後它的父類也繼承的其它的類,那麼在這些被繼承的類中有相同名字的方法時,調用的優先級是有順序的,在看
繼承以前,你們要記住 self 就是對象自己。
在python中,類若是繼承了多個類,那麼找尋的方法有兩種,分別是:深度優先和廣度優先,當類是經典類的時候,多繼承的狀況下,是按照深
度優先的方式查找,當類是新式類的時候會按照廣度優先的方式查找,
經典類:先去D找,D沒有找B,B沒有找A,A沒有找C,若是仍是未找到,則報錯
新式類:先去D找,D沒有找B,B沒有找C,C沒有找A,若是仍是未找到,則報錯
其實python會計算出一個方法解析順序(MRO)列表,這個列表就是一個簡單的全部基類的線性順序列表,也就說python按照這個列表
的順序進行查找
1 class A(object): 2 def prints(self): 3 print("A") 4 5 class B(A): 6 pass 7 def prints(self): 8 print("B") 9 10 class C(A): 11 def prints(self): 12 print("C") 13 14 class D(B,C): 15 pass 16 def prints(self): 17 print("D") 18 19 D().prints() 20 print(D.mro())
接口與歸一化設計
繼承有兩種用途
一:繼承父類的方法,而且作出本身的改變或者擴展(代碼重用)
二:聲明某個子類兼容於某基類,定義一個接口類Interface,接口類中定義了一些接口名(就是函數名)且並未實現接口的功能,子類繼承接
口類,而且實現接口中的功能,也就說父類給子類規定了方法中必須有哪些函數。
爲何要有接口?其實很簡單,就像製做汽車輪胎同樣,無論你的輪胎作的什麼樣,都須要留下與汽車鏈接的接口,而且這個接口各大汽車輪胎廠
商要是同樣的,保證汽車換誰家的輪胎均可以用。
例子中表示 sata和Text兩個類都繼承Interface這個父類,而後讓子類中都有read這個方法。
1 class Interface(): 2 def read(self): 3 pass 4 5 class Sata(Interface): 6 def read(self): 7 print("read Sata") 8 9 class Text(Interface): 10 def read(self): 11 print("read Text") 12 13 s = Sata() 14 s.read()
可是上面代碼中中發現接口類並不能限定子類必須實現什麼功能,這是由於在python中沒有接口的概念,因此想要實現這種接口,能夠藉助第三方
模塊,其次能夠用抽象類模擬接口
http://pypi.python.org/pypi/zope.interface
twisted的twisted\internet\interface.py裏使用zope.interface
文檔https://zopeinterface.readthedocs.io/en/latest/
設計模式:https://github.com/faif/python-patterns
抽象類
抽象類是一個特殊的類,它的特殊之處在於只能被繼承,不能實例化,由於python中沒有接口,因此讓類繼承某個特定的抽象基類,來表示它們支
持抽象基類的接口
抽象了Interface這個基類和抽象read這個方法後,子類 Sata 和 Text就必須有read這個方法,不然會報錯
1 import abc 2 #接口類使用抽象類 3 class Interface(metaclass=abc.ABCMeta): 4 #抽象方法 5 @abc.abstractclassmethod 6 def read(self): 7 pass 8 9 class Sata(Interface): 10 def read(self): 11 print("read Sata") 12 13 class Text(Interface): 14 def read(self): 15 print("read Text") 16 17 s = Sata() 18 s.read()
補充
上面學習了封裝與繼承,在如下的代碼中B的類集成了A的類,而且實例化的對象b執行了 b.test這個方法,那麼最終輸出的 func這個方法是 B.func
緣由是,先找test方法,在B類中沒有找到就找到了A類中,A類中找到了test方法,而後就執行了A中的test,A中的test又調用了func的方法,因此
python又重B類找,在B類中找到了func的方法,就執行了。
1 class A(): 2 def test(self): 3 print("A.test") 4 self.func() 5 def func(self): 6 print("A.func") 7 8 class B(A): 9 def func(self): 10 print("B.func") 11 12 b = B() 13 b.test()
若是,想要執行的是A類中的func,怎麼辦?能夠利用封裝,由於封裝就是變形,變形後就的方法在B類中就找不到了
1 class A(): 2 def test(self): 3 print("A.test") 4 self.__func() 5 def __func(self): 6 print("A.func") 7 8 class B(A): 9 def __func(self): 10 print("B.func") 11 12 b = B() 13 b.test()
多態的意思就是有多種形態,好比文件這個事物,有文本文件有數據文件等等,就像動物這種事物,有豬類,有狗類等等,在python中的序列類型
就是多態的,由於它有列表,元祖,字符串這幾個形態,那麼多態與多態性,是不一樣的概念,多態性是一種特性,就好比python中的len方法,len
方法中能夠傳入任何序列,python並無類型的限定。
下面的代碼中,給func入任何序列均可以輸出序列的長度,因此obj這個參數就是體現的多態性,一個入口函數,有多種實現方式,本質的原理就是
obj有同名的方法,相同的方法可能執行的不一樣的功能,字符串__len__就是統計字符串的長度,列表__len__就是統計列表的長度。
1 a = "123" 2 b = [1,2,3] 3 c = (1,2,3) 4 5 def func(obj): 6 print(obj.__len__()) 7 8 func(a) 9 func(b) 10 func(c)
多態在類中的體現,首先有個動物的基類,動物的基類裏面定義了shout的方法,並要求繼承的子類都要實現shout的方法,而後建立了 Dog類和Cat類
並都有shout的方法,而後給予兩個類實例化出了dog 和cat 兩個實例,到此爲止以上就叫作多態一種動物的事物有多種形態(貓,狗的形態),在下面定
義了func的函數,對於使用這來講,只須要傳入,貓,狗就能夠出發shout的方法,他們不須要關係是怎麼實現的,也不須要更改代碼,因此下面就是體現
的多態性
1 import abc 2 3 class Animal(metaclass=abc.ABCMeta): 4 @abc.abstractclassmethod 5 def shout(self): 6 pass 7 8 class Cat(Animal): 9 def shout(self): 10 print("喵喵") 11 12 class Dog(Animal): 13 def shout(self): 14 print("汪汪") 15 dog = Dog() 16 cat = Cat() 17 18 19 def func(obj): 20 obj.shout() 21 22 func(dog) 23 func(cat)
多態性的優勢
一、增長了程序的靈活性
二、增長了程序的額外可擴展性
就像上面的例子同樣,還能夠產生動物類的豬形態,驢形態等等,那麼使用者都無需更改代碼,只須要把實例傳入func函數便可
property是一種特殊的屬性,訪問它的時候會執行一段功能(函數)而後返回值
1 class Square(): 2 def __init__(self,side_len): 3 self.__side_len = side_len 4 5 #計算正方形的周長 6 @property 7 def perimeter(self): 8 return 4*self.__side_len 9 10 #計算正方形的面積 11 @property 12 def area(self): 13 return self.__side_len*self.__side_len 14 15 #變成數據屬性 @property 就等於一下操做 16 #perimeter = property(perimeter) 17 #area = property(area) 18 19 s = Square(5) 20 #不變形執行的調用方式 21 # print(s.perimeter()) 22 #print(s.area()) 23 #用調用屬性的方式來調用 24 print(s.perimeter) 25 print(s.area)
上面的代碼把函數屬性變成了數據屬性,那麼數據屬性能夠從新賦值,刪除等操做,下面代碼實現了刪除,從新賦值的操做
1 class Square(): 2 def __init__(self,side_len): 3 self.__side_len = side_len 4 5 #讀取邊長 6 @property#讀取 7 def perimeter(self): 8 print("獲取") 9 return self.__side_len 10 11 @perimeter.setter#更改 12 def perimeter(self,value): 13 print("更改") 14 self.__side_len = value 15 16 @perimeter.deleter#刪除 17 def perimeter(self): 18 print("刪除") 19 del self.__side_len 20 21 s = Square(5) 22 print(s.perimeter) 23 s.perimeter = 111 24 del s.perimeter
那麼其實上面的用法意義並不大,意義大的是,咱們能夠利用上面的方法來控制數據屬性的賦值,刪除等只須要在相應的地方,增長相應的邏輯
1 class Square(): 2 def __init__(self,side_len): 3 self.__side_len = side_len 4 5 #讀取邊長 6 @property#讀取 7 def perimeter(self): 8 print("獲取") 9 return self.__side_len 10 11 @perimeter.setter#更改 12 def perimeter(self,value): 13 if not isinstance(value,int): 14 print("更改失敗") 15 else: 16 print("更改完成") 17 self.__side_len = value 18 19 @perimeter.deleter#刪除 20 def perimeter(self): 21 print("刪除") 22 del self.__side_len 23 24 s = Square(5) 25 print(s.perimeter) 26 s.perimeter = "111" 27 s.perimeter = 11 28 print(s.perimeter)
只要是方法就是綁定到實例上的函數,類當中定義的函數都是給實例去用的,可是靜態方法和類方法是給類用的
靜態方法(staticmethod)
staticmethod主要是方便外部的函數繼承到類中,美化代碼結構,重點在不須要類實例化的狀況下調用方法,也不須要傳入self,而且在特定的
地方能夠藉助靜態方法幫咱們實例化,以下的 Date 類,輸出年月日
1 import time 2 class Foo: 3 @staticmethod 4 def spam(x,y,z): 5 print(x,y,z) 6 7 Foo.spam(1,2,3) 8 9 class Date(): 10 def __init__(self,year,mon,day): 11 self.year = year 12 self.mon = mon 13 self.day = day 14 15 def prints(self): 16 print(self.year,self.mon,self.day) 17 18 @staticmethod #等於 now = staticmethod(now) 19 def now(): 20 t = time.localtime() 21 return Date(t.tm_year,t.tm_mon,t.tm_mday) 22 d = Date(2017,1,20) 23 c = Date.now() 24 25 d.prints() 26 c.prints()
類方法(classmethod)
類方法與靜態方法用法很是類似,區別就是被類方法裝飾的函數,會傳入cls,也就是類的自己,誰來調用就把誰傳入進去,那麼有類的自己就可
以操做類的數據屬性和方法屬性,下面的代碼就是經過classmethod給date從新賦值
1 import time 2 class Date(): 3 date = None 4 5 @classmethod #等於 now = staticmethod(now) 6 def now(cls): 7 t = time.localtime() 8 cls.date = [t.tm_year,t.tm_mon,t.tm_mday] 9 10 Date.now() 11 d = Date() 12 print(d.date)
classmethod也能夠藉助它幫咱們實例化
1 class Date(): 2 def __init__(self,year,mon,day): 3 self.year = year 4 self.mon = mon 5 self.day = day 6 7 def prints(self): 8 print(self.year,self.mon,self.day) 9 10 @classmethod #等於 now = staticmethod(now) 11 def now(cls): 12 t = time.localtime() 13 return cls(t.tm_year,t.tm_mon,t.tm_mday) 14 15 d=Date.now() 16 d.prints()
在編程的過程當中,常常會出現一些報錯,那麼爲了保證在出錯的時候程序繼續運行,或者作其它的處理,這時異常處理就極爲重要
語法:
try:
被監控的代碼
except 捕獲的錯誤類型 as 賦值的變量:
其餘操做
先來看一個關於捕獲數據類型異常的代碼,下面的例子很簡單,把data作int轉換,可是data是字符串因此沒法轉換,因此報錯經過 try 和except
能夠捕獲錯誤
1 data = "abc" 2 try: 3 int(data) 4 except ValueError as e: 5 print(e)
在上面的例子中能夠看出,異常處理的捕獲的錯誤類型是不少的,大概有以下這些
1 AttributeError 試圖訪問一個對象沒有的樹形,好比foo.x,可是foo沒有屬性x 2 IOError 輸入/輸出異常;基本上是沒法打開文件 3 ImportError 沒法引入模塊或包;基本上是路徑問題或名稱錯誤 4 IndentationError 語法錯誤(的子類) ;代碼沒有正確對齊 5 IndexError 下標索引超出序列邊界,好比當x只有三個元素,卻試圖訪問x[5] 6 KeyError 試圖訪問字典裏不存在的鍵 7 KeyboardInterrupt Ctrl+C被按下 8 NameError 使用一個還未被賦予對象的變量 9 SyntaxError Python代碼非法,代碼不能編譯(我的認爲這是語法錯誤,寫錯了) 10 TypeError 傳入對象類型與要求的不符合 11 UnboundLocalError 試圖訪問一個還未被設置的局部變量,基本上是因爲另有一個同名的全局變量, 12 致使你覺得正在訪問它 13 ValueError 傳入一個調用者不指望的值,即便值的類型是正確的
1 BaseException 全部異常的基類 2 SystemExit 解釋器請求退出 3 KeyboardInterrupt 用戶中斷執行(一般是輸入^C) 4 Exception 常規錯誤的基類 5 StopIteration 迭代器沒有更多的值 6 GeneratorExit 生成器(generator)發生異常來通知退出 7 StandardError 全部的內建標準異常的基類 8 ArithmeticError 全部數值計算錯誤的基類 9 FloatingPointError 浮點計算錯誤 10 OverflowError 數值運算超出最大限制 11 ZeroDivisionError 除(或取模)零 (全部數據類型) 12 AssertionError 斷言語句失敗 13 AttributeError 對象沒有這個屬性 14 EOFError 沒有內建輸入,到達EOF 標記 15 EnvironmentError 操做系統錯誤的基類 16 IOError 輸入/輸出操做失敗 17 OSError 操做系統錯誤 18 WindowsError 系統調用失敗 19 ImportError 導入模塊/對象失敗 20 LookupError 無效數據查詢的基類 21 IndexError 序列中沒有此索引(index) 22 KeyError 映射中沒有這個鍵 23 MemoryError 內存溢出錯誤(對於Python 解釋器不是致命的) 24 NameError 未聲明/初始化對象 (沒有屬性) 25 UnboundLocalError 訪問未初始化的本地變量 26 ReferenceError 弱引用(Weak reference)試圖訪問已經垃圾回收了的對象 27 RuntimeError 通常的運行時錯誤 28 NotImplementedError 還沒有實現的方法 29 SyntaxError Python 語法錯誤 30 IndentationError 縮進錯誤 31 TabError Tab 和空格混用 32 SystemError 通常的解釋器系統錯誤 33 TypeError 對類型無效的操做 34 ValueError 傳入無效的參數 35 UnicodeError Unicode 相關的錯誤 36 UnicodeDecodeError Unicode 解碼時的錯誤 37 UnicodeEncodeError Unicode 編碼時錯誤 38 UnicodeTranslateError Unicode 轉換時錯誤 39 Warning 警告的基類 40 DeprecationWarning 關於被棄用的特徵的警告 41 FutureWarning 關於構造未來語義會有改變的警告 42 OverflowWarning 舊的關於自動提高爲長整型(long)的警告 43 PendingDeprecationWarning 關於特性將會被廢棄的警告 44 RuntimeWarning 可疑的運行時行爲(runtime behavior)的警告 45 SyntaxWarning 可疑的語法的警告 46 UserWarning 用戶代碼生成的警告
對於上述,只能捕獲指定類型的異常,那麼出現指定類型外的錯誤就會報錯,因此python中有一種萬能異常(Exception)
1 data = "abc" 2 try: 3 int(data) 4 tuple(data) 5 except Exception as e: 6 print(e) 7 print(data)
還有一點要注意的是,一旦發生異常代碼就會從發生異常的代碼位置跳轉到 except 中,因此不會繼續執行 tuple(data)這行代碼
異常的其它用法
一、其它異常結構
1 try: 2 # 主代碼塊 3 pass 4 except Exception as e: 5 # 異常時,執行該塊 6 pass 7 else: 8 # 主代碼塊執行完,執行該塊 9 pass 10 finally: 11 # 不管異常與否,最終執行該塊 12 pass
二、主動觸發異常
1 try: 2 raise Exception('發生了錯誤。。。') 3 except Exception as e: 4 print(e)
三、自定義異常
1 class MyException(Exception): 2 3 def __init__(self, msg): 4 self.message = msg 5 6 def __str__(self): 7 return self.message 8 9 try: 10 raise MyException('個人異常') 11 except MyException as e: 12 print(e)
四、斷言
使用assert斷言是學習python一個很是好的習慣,斷言句語格式及用法很簡單。在沒完善一個程序以前,咱們不知道程序在哪裏會出錯,與其讓
它在運行最崩潰,不如在出現錯誤條件時就崩潰,這時候就須要assert斷言的幫助。
1 a = 2 2 assert 1==1 3 assert 2+2==2*2 4 assert range(4)==[0,1,2,3] 5 assert a == 3
做者:北京小遠
出處:http://www.cnblogs.com/bj-xy/ 本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。