一.類的約束java
約束是對類的約束python
有兩種方法:程序員
1.提取一個父類,在父類中給出一個方法,而且在方法中不給出任何代碼,直接拋異常函數
class Base: def login(self): raise Exception("你沒有實現login方法()") class Normal(Base): def login(self): pass class Member(Base): def denglu(self): pass class Admin(Base): def login(self): pass
# 項目經理寫的總入口 def login(obj): print("準備驗證碼.......") obj.login() print("進入主頁.......")
n = Normal() m = Member() a = Admin() login(n) login(m) # 報錯. login(a)
在執行到login(m)的時候程序會報錯. 緣由是, 此時訪問的login()是父類中的方法. 可是父類中的方法會拋出一個異常. 因此報錯. 這樣程序員就不得不寫login方法了. 從而對子類進行了相應的約束. 在本示例中. 要注意. 咱們拋出的是Exception異常. 而Exception是全部異常的根. 咱們沒法經過這個異常來判斷出程序是由於什麼報的錯. 因此. 最好是換一個比較專業的錯誤信息. 最好是換成NotImplementError. 其含義是. "沒有實現的錯誤". 這樣程序員或者項目經理能夠一目瞭然
的知道是什麼錯了. 就比如. 你犯錯了. 我就告訴你犯錯了. 你也不知道哪裏錯了. 這時我告訴你, 你xxx錯了. 你改也好改不是?
2.寫抽象類和抽象方法,這種方案相對來講比上一個麻煩一些.須要你們先引入一個抽象的概念,咱們若是寫一個方法,不知道方法的內部應該到底寫什麼,那這個方法就應該是一個抽象方法,若是一個類包含抽象方法,那麼這個類必定是一個抽象類.抽象類是不能有測試
實例的spa
在python中編寫一個抽象類比較麻煩. 須要引入abc模塊中的ABCMeta和abstractmethod這兩個內容. 來咱們看一個例子. from abc import ABCMeta, abstractmethod # 類中包含了抽象方法. 那此時這個類就是個抽象類. 注意: 抽象類能夠有普通方法 class IGame(metaclass=ABCMeta): # 一個遊戲到底怎麼玩兒? 你能形容? 流程能同樣麼? @abstractmethod def play(self): pass def turn_off(self): print("破B遊戲不玩了, 脫坑了") class DNFGame(IGame): # 子類必須實現父類中的抽象方法. 不然子類也是抽象類 def play(self): print("dnf的玩兒法") # g = IGame() # 抽象類不能建立對象 dg = DNFGame() dg.play() 經過代碼咱們能發現. 這裏的IGame對DNFGame進行了約束. 換句話說. 父類對子類進行了約束
接下來. 繼續解決咱們一開始的問題. from abc import ABCMeta, abstractmethod class Base(metaclass=ABCMeta): @abstractmethod def login(self): pass class Normal(Base): def login(self): pass class Member(Base): def denglu(self): # 這個就沒用了 pass def login(self): # 子類對父類進行實現 pass class Admin(Base): def login(self): pass # 項目經理寫的總入口 def login(obj): print("準備驗證碼.......") obj.login() print("進入主頁.......") n = Normal() m = Member() a = Admin() login(n) login(m) login(a) 總結: 約束. 其實就是父類對子類進行約束. 子類必需要寫xxx方法. 在python中約束的方式和方法有兩種: 1. 使用抽象類和抽象方法, 因爲該方案來源是java和c#. 因此使用頻率仍是不多的 2. 使用人爲拋出異常的方案. 而且儘可能拋出的NotImplementError. 這樣比較專業, 並且錯誤比較明確.(推薦)
二.異常處理調試
什麼是異常?異常是程序在運行過程當中產生的錯誤,若是程序出現了異常,怎麼處理呢?code
def chu(a, b): return a/b try: ret = chu(10, 0) print(ret) except Exception as e: print("除數不能是0") 結果: 除數不能是0 那try...except是什麼意思呢? 嘗試着運行xxxxx代碼. 出現了錯誤. 就執行except後面的代碼. 在這個過程當中. 當代碼出現錯誤的時候. 系統會產生一個異常對象. 而後這個異常會向外拋. 被except攔截. 並把接收到的異常對象賦值給e. 這裏的e就是異常對象. 那這裏的
Exception是什麼?Exception是全部異常的基類, 也就是異常的跟. 換句話說. 全部的錯誤都是Exception的子類對象. 咱們看到的ZeroDivisionError 其實就是Exception的子類. 那這樣寫好像有點問題. Exception表示全部的錯誤. 太籠統了. 全部的錯誤都會被認爲是Exception.
當程序中出現多種錯誤的時候, 就很差分類了, 最好是出什麼異常就用什麼來處理. 這樣就更加合理了.因此在try...execpt語句中. 還能夠寫更多的except.
給出一個完整的異常處理方法(語法):orm
try: '''操做''' except Exception as e: '''異常的父類,能夠捕獲全部的異常''' else: '''保護不拋出異常的代碼, 當try中無異常的時候執⾏''' finally: '''最後老是要執行我'''
解讀: 程序先執行操做, 而後若是出錯了會走except中的代碼. 若是不出錯, 執行else中的代碼. 不論出不出錯. 最後都要執行finally中的語句. 通常咱們用try...except就夠用了. 頂多加上finally. finally通常用來做爲收尾工做.對象
def add(a, b): ''' 我傳遞兩個整數. 我幫你計算兩個數的和 :param :param a: :param :param b: :return :return: ''' if not type(a) == int and not type(b) == int: # 當程序運行到這句話的時候. 整個函數的調用會被中斷. 並向外拋出一個異常. raise Exception("不是整數, 朕不能幫你搞定這麼複雜的運算.") return a + b # 若是調用方不處理異常. 那產生的錯誤將會繼續向外拋. 最後就拋給了用戶 # add("你好", "我叫賽利亞") # 若是調用方處理了異常. 那麼錯誤就不會丟給用戶. 程序也能正常進行 try: add("胡辣湯", "滋滋冒油的大腰子") except Exception as e: print("報錯了.本身處理去吧")
當程序運行到raise. 程序會被中斷. 並實例化後面的異常對象. 拋給調用方. 若是調用方不處理. 則會把錯誤繼續向上拋出. 最終拋給用戶. 若是調用方處理了異常. 那程序能夠正常的進行執行.
自定義異常: 很是簡單. 只要你的類繼承了Exception類. 那你的類就是一個異常類. 就這麼簡單.
# 繼承Exception. 那這個類就是一個異常類 class GenderError(Exception): pass class Person: def __init__(self, name, gender): self.name = name self.gender = gender def nan_zao_tang_xi_zao(person): if person.gender != "男": raise GenderError("性別不對. 這裏是男澡堂⼦") p1 = Person("alex", "男") p2 = Person("eggon", "蛋") # nan_zao_tang_xi_zao(p1) # nan_zao_tang_xi_zao(p2) # 報錯. 會拋出一個異常: GenderError # 處理異常 try: nan_zao_tang_xi_zao(p1) nan_zao_tang_xi_zao(p2) except GenderError as e: print(e) # 性別不對, 這裏是男澡堂子 except Exception as e: print("反正報錯了")
若是是真的報錯了. 咱們在調試的時候, 最好是能看到錯誤源自於哪裏? 怎麼辦呢? 須要引入另外一個模塊traceback. 這個模塊能夠獲取到咱們每一個方法的調用信息. 又被成爲堆棧信息. 這個信息對咱們拍錯是頗有幫助的.
import traceback # 繼承Exception. 那這個類就是一個異常類 class GenderError(Exception): pass class Person: def __init__(self, name, gender): self.name = name self.gender = gender def nan_zao_tang_xi_zao(person): if person.gender != "男": raise GenderError("性別不對. 這裏是男澡堂子") p1 = Person("alex", "男") p2 = Person("eggon", "蛋") # nan_zao_tang_xi_zao(p1) # nan_zao_tang_xi_zao(p2) # 報錯. 會拋出一個異常: GenderError # 處理異常 try: nan_zao_tang_xi_zao(p1) nan_zao_tang_xi_zao(p2) except GenderError as e: val = traceback.format_exc() # 獲取到堆棧信息 print(e) # 性別不對. 這裏是男澡堂子 print(val) except Exception as e: print("反正報錯了") #性別不對. 這裏是男澡堂子 Traceback (most recent call last): File "D:/python_qishi/day021練習/練習.py", line 66, in <module> nan_zao_tang_xi_zao(p2) File "D:/python_qishi/day021練習/練習.py", line 58, in nan_zao_tang_xi_zao raise GenderError("性別不對. 這裏是男澡堂子") GenderError: 性別不對. 這裏是男澡堂子
當測試代碼的時候把堆棧信息打印出來. 可是當到了線上的生產環境的時候把這個堆棧去掉便可.