1. 程式人生 > >python記錄_day019 類的約束 異常處理 日誌

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): 24
obj.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系統')  #寫入日誌資訊
日誌分開