###### tags: `python`
# 除錯與異常處理
## 例外
* 語法錯誤(syntax error):不符合python程式撰寫規則
* 沒有縮排
* 拼錯python指令、參數格式不符合函數要求
* 不管如何執行時一定會發生錯誤
* 比較容易除錯
* 執行期間錯誤(runtime error):執行程式時發生的錯誤
* 使用者輸入預期以外的資料
* 系統軟硬體出現異常
* 執行時可能正常也可能發生錯誤,端看使用者輸入資料或操作而定
* 邏輯錯誤(logic error):沒有任何錯誤訊息,但程式邏輯不符合商業邏輯
* 使用者登入後可瀏覽其他使用者的檔案資訊
---
當錯誤發生時程式就被中斷並產生讓使用者害怕的錯誤畫面
### 範例1
```python=
x = int(input("input first num: "))
y = int(input("input second num: "))
z = x / y
print(z)
```
透過try...except補抓錯誤狀態,導向使用者理解的錯誤訊息
並讓程式仍然可以正常繼續運作
### 範例2
```python=
while True:
try:
x = int(input("input first num: "))
y = int(input("input second num: "))
z = x / y
except:
print("error")
print(z)
```
發生不同錯誤顯示不同錯誤訊息
讓錯誤訊息更加明確具體
### 範例3
```python=
while True:
try:
x = int(input("input first num: "))
y = int(input("input second num: "))
z = x / y
print(z)
except ZeroDivisionError:
print("y can't be zero")
except ValueError:
print("please input number")
except:
print("error")
```
顯示python預設錯誤訊息
### 範例4
```python=
while True:
try:
x = int(input("input first num: "))
y = int(input("input second num: "))
z = x / y
print(z)
except ZeroDivisionError:
print("y can't be zero")
except Exception as e:
print(e)
```
**else**: 當沒有發生任何錯誤時執行
**finally**: 不管有沒有發生錯誤都要執行這一行
### 範例5
```python=
count = 0
while True:
try:
x = int(input("input first num: "))
y = int(input("input second num: "))
z = x / y
except Exception as e:
print(e)
else:
print(z)
finally:
count += 1
print("count: ", count)
```
在開發函數、物件、套件時,我們會在開發者不正確使用時故意產生錯誤
提醒開發者錯誤發生在哪裡
避免開發者最後才知道不正確
而需要整個程式碼下去一個一個除錯
浪費大量成本
### 範例6
```python=
try:
x = int(input('num: '))
if x >= 100:
raise NameError("數字不可大於100")
elif x < 0:
raise NameError("數字不可小於0")
except Exception as e:
print(e)
```
---
## 日誌(log)
* 可控制除錯訊息顯示或不顯示
* 方便將除錯資訊寫入檔案
### 日誌等級
由高到低
* **危急(critical)**:顯示發生系統或電腦嚴重當機時的資訊
* **錯誤(error)**:顯示發生錯誤時的資訊
* **警告(warning)**:顯示可能會發生錯誤時的資訊
* **資訊(info)**:顯示一般事件發生時的資訊,例如執行某函數或觸發某事件
* **除錯(debug)**:顯示關鍵變數變化的資訊
### 範例7
各位可以試者修改第三行,將logging.basicConfig(level=**logging.DEBUG**)
改成logging.basicConfig(level=**logging.ERROR**)
看看執行結果會有什麼變化
```python=
import logging
logging.basicConfig(level=logging.DEBUG)
logging.debug('DEBUG level message')
logging.info('INFO level message')
logging.warning('WARNING level message')
logging.error('ERROR level message')
logging.critical('CRITICAL level message')
```
### 範例8
```python=
import logging
logging.basicConfig(level=logging.ERROR)
while True:
try:
x = int(input("input first num: "))
y = int(input("input second num: "))
logging.debug("x: "+ str(x))
logging.debug("y: "+ str(y))
z = x / y
print(z)
except ZeroDivisionError:
logging.error("y can't be zero")
except Exception as e:
logging.error(e)
```
### 範例9
透過logging.info顯示進入、離開函數showMsg訊息
```python=
#-*- coding:utf-8 -*-
import logging
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s: %(message)s')
def showMsg():
logging.info('執行showMsg函數')
print("hello")
logging.info('結束showMsg函數')
showMsg()
```
### 範例10
試者註解掉37~42行看看有什麼變化
```python=
import logging
logging.basicConfig(level=logging.DEBUG, format='[%(asctime)s] %(levelname)s: %(message)s')
class Animal:
logging.info('run class Animal')
def __init__(self, head, hand, foot):
logging.info('run class Animal: __init__()')
self.head = head
self.hand = hand
self.foot = foot
def run(self):
logging.info('run class Animal: run()')
return '使用身體快速移動'
class Bird(Animal):
logging.info('run class Bird')
def __init__(self, head, wing, foot):
logging.info('run class Bird: __init__()')
self.head = head
self.wing = wing
self.foot = foot
def run(self):
logging.info('run class Bird: run()')
return '使用雙腳奔跑'
def fly(self):
logging.info('run class Bird: fly()')
return '使用翅膀飛翔'
if __name__ == '__main__':
animal = Animal(1, 0, 4)
print(animal.run())
bird = Bird(1, 2, 2)
print(bird.run())
print(bird.fly())
```
----
## 格式化除錯訊息
### 範例11
```python=
#-*- coding:utf-8 -*-
import logging
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s: %(message)s')
logging.debug('除錯訊息')
logging.info('資訊訊息')
logging.warning('警告訊息')
logging.error('錯誤訊息')
logging.critical('危急訊息')
```
### 輸出除錯訊息到檔案
### 範例12
```python=
import logging
logging.basicConfig(level=logging.DEBUG, filename='debug.log', format='%(asctime)s - %(levelname)s: %(message)s')
while True:
try:
x = int(input("input first num: "))
y = int(input("input second num: "))
logging.debug("x: "+ str(x))
logging.debug("y: "+ str(y))
z = x / y
print(z)
except ZeroDivisionError:
logging.error("y can't be zero")
except Exception as e:
logging.error(e)
```