python記錄_day019 類的約束 異常處理 日誌
一 、約束
python中約束有兩種
第一種,通過拋異常進行約束,這種是子類不按我要求的來,我就給你拋異常(推薦)
操作:提取一個父類. 在父類中給出一個方法。但在方法中不給出任何程式碼,直接拋異常
1 # 貼吧 2 # 專案經理(級別高一點兒) 3 class Base: 4 def login(self): # 強制子類做xxxx事 5 raise NotImplementedError("子類沒有實現該方法") # 報錯. 拋異常 6 7 # 1. 普通賬號 --> 翔哥 8 class Normal(Base):異常約束9 def login(self): 10 print("普通賬號的登入") 11 12 # 2. 吧務 - > 強哥 13 class Member(Base): 14 def login(self): 15 print("吧務的登入") 16 17 # 3. 百度員工 -> 明哥 18 class Admin(Base): 19 def denglu(self): 20 print("管理員的登入") 21 22 # 專案經理 23 def wodetian(obj): 24obj.login() 25 26 n = Normal() 27 wodetian(n) 28 29 m = Member() 30 wodetian(m) 31 32 a = Admin() 33 wodetian(a) #這就會丟擲異常,因為沒按要求寫,找不到login
第二種,通過抽象類和抽象方法進行約束,這種是子類不按我要求的來,我就不讓子類例項化
操作:提取一個父類,將父類中給出的方法定義為抽象方法,不必實現,直接pass
### 這些概念要記住:
抽象類是不能進行例項化的
如果一個類中有抽象方法,那麼這個類就是抽象類
一個抽象類可以有非抽象方法
1 from abc import ABCMeta, abstractmethod 2 3 class Base(metaclass=ABCMeta): # 抽象類 4 # 抽象方法 5 @abstractmethod 6 def login(self): # 強制子類做xxxx事,子類必須重寫這個方法 7 pass 8 9 class Normal(Base): 10 def login(self): 11 print("普通登入") 12 13 class Member(Base): 14 def login(self): 15 print("會員登入") 16 17 class Admin(Base): 18 def denglu(self): 19 print('管理員登入') 20 21 def denglu(obj): 22 obj.login() 23 n = Normal() 24 denglu(n) 25 m = Member() 26 denglu(m) 27 a = Admin() #Can't instantiate abstract class admin with abstract methods login 28 denglu(a)抽象約束
二、異常處理
格式:
try:
程式碼塊
except 錯誤名 as 別名:
出現該錯誤時做什麼
except 錯誤名 as 別名:
出現該錯誤時做什麼
...
else:
不出錯時執行這裡
finally:
出不出錯都執行這裡
解讀: 程式先執行操作, 然後如果出錯了會走except中的程式碼. 如果不出錯, 執行else中的程式碼. 不論出不出錯. 最後都要執行finally中的語句. 一般我們用try...except就夠了. 頂多加上finally. finally一般用來作為收尾工作。
1 def cul(a,b): 2 if (type(a)== int or type(a) == float) and (type(b)== int or type(b)== float): 3 return a+b 4 else: 5 raise Exception("我要的是數字,你輸入的是啥") 6 7 try: 8 print(cul("一",4)) 9 except Exception as e: 10 print("錯了,你要輸入數字")異常處理
##拋異常
拋異常要用到關鍵字raise
1 def add(a, b): 2 ''' 3 給我傳遞兩個整數. 我幫你計算兩個數的和 4 :param :param a: 5 :param :param b: 6 :return :return: 7 ''' 8 if not type(a) == int and not type(b) == int: 9 # 當程式執行到這句話的時候. 整個函式的呼叫會被中斷. 並向外丟擲一個異常. 10 raise Exception("不是整數, 朕不能幫你搞定這麼複雜的運算.") 11 return a + b 12 # 如果呼叫方不處理異常. 那產生的錯誤將會繼續向外拋. 最後就拋給了使用者 13 add("你好", "我叫賽利亞") 14 # 如果呼叫方處理了異常. 那麼錯誤就不會丟給使用者. 程式也能正常進行 15 try: 16 add("胡辣湯", "滋滋冒油的大腰子") 17 except Exception as e: 18 print("報錯了. 我要的是數字")raise
##自定義異常
非常簡單. 只要你的類繼承了Exception類. 那你的類就是一個異常類
格式:
def 異常名(Exception):
pass
1 #自定義異常 2 class GenderException(Exception): 3 pass 4 5 class Person: 6 7 def __init__(self,name,gender): 8 self.name = name 9 self.gender = gender 10 11 def goto_nan(self): 12 if self.gender !="男": 13 raise GenderException("性別不對") 14 else: 15 print("歡迎光臨") 16 try: 17 p1 = Person('alex', '男') 18 p1.goto_nan() 19 20 p2 = Person('妖姬', '女') 21 p2.goto_nan() 22 23 except GenderException as e: 24 print("你來錯地兒了") 25 except Exception as e: 26 print("其他錯誤")自定義異常
##異常處理好是好,但是有一個問題,我們在除錯的時候是希望看到程式哪裡出現問題的,而異常處理沒有具體的錯誤資訊,那這麼辦呢?這時需要引入另一個模組traceback. 這個模組可以獲取到我們每個方法的呼叫資訊. 又被稱為堆疊資訊. 這個資訊對我們排錯是很有幫助的.
1 import traceback 2 3 # 繼承Exception. 那這個類就是一個異常類 自定義異常 4 class GenderError(Exception): 5 pass 6 class Person: 7 def __init__(self, name, gender): 8 self.name = name 9 self.gender = gender 10 11 def nan_zao_tang_xi_zao(person): 12 if person.gender != "男": 13 raise GenderError("性別不對. 這裡是男澡堂子") 14 15 p1 = Person("alex", "男") 16 p2 = Person("eggon", "蛋") 17 # nan_zao_tang_xi_zao(p1) 18 # nan_zao_tang_xi_zao(p2) # 報錯. 會丟擲一個異常: GenderError 19 20 # 處理異常 21 try: 22 nan_zao_tang_xi_zao(p1) 23 nan_zao_tang_xi_zao(p2) 24 except GenderError as e: 25 val = traceback.format_exc() # 獲取到堆疊資訊 26 print(e) # 性別不對. 這裡是男澡堂子 27 print(val) 28 except Exception as e: 29 print("反正報錯了") 30 結果: 31 性別不對. 這裡是男澡堂子 32 Traceback (most recent call last): 33 File "/Users/sylar/PycharmProjects/oldboy/面向物件/day05.py", line 155, in 34 <module> 35 nan_zao_tang_xi_zao(p2) 36 File "/Users/sylar/PycharmProjects/oldboy/面向物件/day05.py", line 144, in 37 nan_zao_tang_xi_zao 38 raise GenderError("性別不對. 這裡是男澡堂子") 39 GenderError: 性別不對. 這裡是男澡堂子View Code
這樣我們就能收放放如了. 當測試程式碼的時候把堆疊資訊打印出來. 但是當到了 線上的生產環境的時候把這個堆疊去掉即可
三、日誌(不用記,知道怎麼用就行)
當出現任何錯誤的時候. 我們都可以去日誌系統裡去查. 看哪裡出了問題. 這樣在解決問題和bug的時候就多了一個幫手。
那如何在python中建立這個日誌系統呢?
1. 匯入logging模組.
2. 簡單配置一下logging
3. 出現異常的時候(except). 向日志裡寫錯誤資訊.
1 #引數解釋 2 # filename: 檔名 3 # format: 資料的格式化輸出. 最終在日誌檔案中的樣子 4 # 時間-名稱-級別-模組: 錯誤資訊 5 # datefmt: 時間的格式 6 # level: 錯誤的級別權重, 當錯誤的級別權重大於等於leval的時候才會寫入檔案 7 8 import logging #匯入模組 9 #簡單配置,一般只需修改level值 10 logging.basicConfig(filename='x1.txt', 11 format='%(asctime)s - %(name)s - %(levelname)s -% 12 (module)s: %(message)s', 13 datefmt='%Y-%m-%d %H:%M:%S', 14 level=0) # 當前配置表示 0以上的分數會被寫入檔案 15 # CRITICAL = 50 16 # FATAL = CRITICAL 17 # ERROR = 40 18 # WARNING = 30 19 # WARN = WARNING 20 # INFO = 20 21 # DEBUG = 10 22 # NOTSET = 0 23 logging.critical("我是critical") # 寫入critical級別資訊 24 logging.error("我是error") # 寫入error級別資訊 25 logging.warning("我是警告") # 警告 26 logging.info("我是基本資訊") # 27 logging.debug("我是除錯") 28 logging.log(2, "我是自定義") # 自定義. 第一個引數可以自己給值,第二個是往日誌檔案裡寫的內容
1 1 import logging 2 2 3 3 logging.basicConfig(filename='x1.log', 4 4 format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', 5 5 datefmt='%Y-%m-%d %H:%M:%S', 6 6 level=35) # 當前配置表示 35以上的級別會被寫入檔案 7 7 8 8 import traceback 9 9 try: 10 10 print(1/0) 11 11 except Exception: 12 12 logging.error(traceback.format_exc()) # 寫入error資訊 13 13 logging.log(36, traceback.format_exc()) # 自定義寫入 14 14 print("出錯了") 15 15 結果: 16 16 x1.txt內容 17 17 18 18 2018-11-12 20:43:01 - root - ERROR -日誌系統: Traceback (most recent call last): 19 19 File "D:/PyCharm/workspace/day019 約束/日誌系統.py", line 29, in <module> 20 20 print(1/0) 21 21 ZeroDivisionError: division by zero 22 22 23 23 2018-11-12 20:43:01 - root - Level 36 -日誌系統: Traceback (most recent call last): 24 24 File "D:/PyCharm/workspace/day019 約束/日誌系統.py", line 29, in <module> 25 25 print(1/0) 26 26 ZeroDivisionError: division by zero日誌應用
##
最後, 如果你係統中想要把日誌檔案分開. 比如. 有個大專案, 有兩個子系統, 那兩個子系 統要分開記錄日誌. 方便除錯. 那怎麼辦呢? 注意. 用上面的basicConfig是搞不定的. 我們要藉助檔案助手(FileHandler), 來幫我們完成日誌的分開記錄
1 import logging 2 3 # 建立一個操作日誌的物件logger(依賴FileHandler) 4 file_handler = logging.FileHandler('l1.log', 'a', encoding='utf-8') 5 file_handler.setFormatter(logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s")) 6 7 logger1 = logging.Logger('a系統', level=logging.ERROR) #級別 8 logger1.addHandler(file_handler) #把檔案助手和日誌物件繫結 9 logger1.error('我是A系統') #寫入日誌資訊 10 11 # 再建立一個操作日誌的物件logger(依賴FileHandler) 12 file_handler2 = logging.FileHandler('l2.log', 'a', encoding='utf-8') 13 file_handler2.setFormatter(logging.Formatter(fmt="%(asctime)s - %(name)s -%(levelname)s -%(module)s: %(message)s")) 14 15 logger2 = logging.Logger('b系統', level=logging.ERROR) #級別 16 logger2.addHandler(file_handler2) 17 logger2.error('我是B系統') #寫入日誌資訊日誌分開