錯誤和異常處理
Python有兩種錯誤很容易辨認:語法錯誤和異常。
1 什麽是異常?
異常即是一個事件,該事件會在程序執行過程中發生,影響了程序的正常執行。
一般情況下,在Python無法正常處理程序時就會發生一個異常。
如:有些是由於拼寫、配置、選項等等各種引起的程序錯誤,有些是由於程序功能處理邏輯不完善引起的漏洞,這些統稱為程序中的異常
異常是Python對象,表示一個錯誤。
當Python腳本發生異常時我們需要捕獲處理它,否則程序會終止執行。
常見異常如:
-
語法錯誤:SyntaxError:invalid syntax
2018-04-02_215304.png
2.變量名不存在:NameError:name ‘b‘ is not defined
2018-04-02_215935.png
3.索引錯誤:IndexError: list index out of range
2018-04-02_220226.png
4.關鍵字錯誤:KeyError: ‘c‘
2018-04-02_220450.png
5.類型錯誤:TypeError: list indices must be integers, not str
2018-04-02_220741.png
6.參數傳值錯誤:ValueError: invalid literal for int() with base 10: ‘ab‘(主要發生在函數裏面)
2018-04-02_221813.png
7.屬性錯誤:AttributeError: A instance has no attribute ‘acc‘
2018-04-02_222234.png
8.輸入輸出錯誤:IOError
2018-04-02_222542.png
解決方案◆
- 如果是拼寫、配置等等引起的錯誤,根據出錯信息進行排查錯誤出現的位置進行解決
- 如果是程序設計不完善引起的漏洞,根據漏洞的情況進行設計處理漏洞的邏輯;
2 錯誤處理
錯誤的出現,在程序中一般會有兩種表現,一種是拼寫錯誤,一種是程序執行過程中出現的錯誤,這樣兩種不同的錯誤應該怎麽進行追蹤和處理呢?
2.1. 拼寫錯誤
常規情況下,拼寫錯誤只是在簡單的記事本等環境下進行開發時,容易手誤產生拼寫錯誤;當前開發環境下,我們經常使用一些半自動化的IDE開發工具,如pycharm等等,可以進行簡單的程序關鍵字的拼寫檢查以及程序結構的檢查,把一些簡單的拼寫問題掐死在萌芽之中
2.2程序運行時錯誤
程序運行過程中,也會出現各種各樣的錯誤,對於錯誤的出現和提示信息必須有一個比較明確的掌握,才能在後續的程序開發中快速的開發並且修復問題,這裏就會出現兩個步驟
- 確定問題及問題出現的代碼行
- 後續的問題處理【參考後面的異常處理】
3 異常處理方式
python程序中出現的異常信息,主要有兩種處理操作方式
? 直接處理異常,保證程序正常執行
? 拋出異常,告知調用者出現的重要錯誤信息
捕捉異常可以使用try/except語句。
(1). 直接處理異常
c = int(input("請輸入整數選項:")) print("用戶輸入了:%d" % c)
上述代碼,正常執行過程中,如果用戶輸入了字母會出現ValueError異常錯誤信息
請輸入整數選項:d
Traceback (most recent call last):
File "D:/Py1801_B/DATE2/python高級/多線程/text.py", line 18, in <module>
c = int(input("請輸入整數選項:"))
ValueError: invalid literal for int() with base 10: ‘d‘
捕捉異常
# 捕捉異常 1
try:
c = int(input("請輸入整數選項:"))
print("用戶輸入了:%d" % c) # 處理異常
except:
print("出現了異常,用戶輸入了非法數據")
通過try捕捉可能出現的異常,如果出現異常~並不讓程序直接崩潰退出,而是執行except中的代碼塊來處理出現的異常
上述代碼中,可以通過except處理在try代碼塊中出現的任意異常
#捕捉異常2
try:
c = int(input("請輸入整數選項:"))
print("用戶輸入了:%d" % c) # 處理指定異常
except ValueError:
print("出現了異常,用戶輸入了非法數據")
可以在except關鍵字後面,添加指定的異常名稱,來處理指定的異常;只有捕捉到該指定異常時except代碼塊才會執行
(2) .給異常信息定義別名
# 捕捉異常
try:
c = int(input("請輸入整數選項:"))
print("用戶輸入了:%d" % c)
# 處理指定的異常並獲取異常信息
except ValueError as e:
print("出現了異常,用戶輸入了非法數據", e)
上述代碼中,在except中指定了處理的異常信息,並且通過as別名的方式將異常信息保存在了一個變量e中,後續可以通過變量e打印出現的異常信息
(3). 精確、同時處理多個異常
try:
# 可能會出現文件找不到的異常:FileNotFoundError
file = open("d:/test.txt", "r")
# 可能會出現類型異常:ValueError
c = int(input("請輸入整數選項:"))
print("用戶輸入了:%d" % c)
# 指定需要處理的多個異常類型,包含在一個元組中
except (ValueError, FileNotFoundError) as e:
print("出現了異常", e)
運行結果:
出現了異常 [Errno 2] No such file or directory: ‘d:/test.txt‘
如上述代碼所示,將多個需要處理的異常信息,進行精確的異常捕捉來提高程序代碼的容錯性能
(4). 精確、分步處理多個異常
try:
# 可能會出現文件找不到的異常:FileNotFoundError
file = open("d:/test.txt", "r")
# 可能會出現類型異常:ValueError
c = int(input("請輸入整數選項:"))
print("用戶輸入了:%d" % c)
# 指定需要處理的多個異常類型,可以通過多個except疊加完成
except ValueError as e:
print("出現了非法輸入異常", e)
except FileNotFoundError as e:
print("文件操作出現異常", e)
except Exception as e:
print("程序中出現了異常", e)
通過多個except疊加,進行異常的精確捕捉和精確處理
(5). 異常處理關鍵字finally
try:
f = open("d:/oCam.rar", "rb")
except FileNotFoundError as e:
print("文件操作出現異常", e)
except Exception as e:
print("程序中出現了異常", e)
finally:
# finally模塊中的代碼,不論是否出現異常,最終都會執行的代碼塊
# 關閉文件,釋放資源
f.close()
finally關鍵字比較特殊,主要是針對異常處理過程中的兩種分支進行一個統一的處理
代碼中根據是否出現異常會出現兩個分支
分支一:代碼中沒有異常,try中的代碼正常執行結束
分支二:代碼中出現異常,從異常代碼開始執行except中的代碼
但是不論執行那個分支,最後進行統一的資源回收時必須執行相同的代碼,所以finally關鍵字就出現了
(6). 異常處理關鍵字else
‘‘‘
try:
# 可能出現異常的代碼
except ValueError as e:
# 處理異常的代碼
except FileNotFoundError as e:
# 處理異常的代碼
except:
# 異常的通用處理
[else:]
[# try中沒有異常,才會執行的代碼]
[finally:]
[# 無論try中是否出現異常,都會執行的代碼]
‘‘‘
try:
f = open("d:/test.txt", "rb")
except FileNotFoundError as e:
print("文件操作出現異常", e)
except Exception as e:
print("程序中出現了異常", e)
else:
print("try中沒有出現異常")
finally:
# finally模塊中的代碼,不論是否出現異常,最終都會執行的代碼塊
# 關閉文件,釋放資源
f.close()
else關鍵字是一種語法糖,主要是將try中的代碼進行了分離處理,將可能出現異常的代碼和之後的代碼分別安排在了不同的代碼塊中,主要目的是提高程序代碼的可讀性;但是實際項目操作過程中使用並不是很多,尤其是在try中或者except中出現了if語句的時候,else關鍵字使用反倒並不是盡如人意了。
(7). 拋出異常
# raise ValueError("出現錯誤")
try:
c = int(input("請輸入選項:"))
print("用戶輸入了選項:%d" % c)
except ValueError as e:
# 轉換成一個比較清楚的異常
# 但是問題是:直接使用系統的異常名稱,不是特別友好!
raise ValueError("類型轉換錯誤")
拋出異常:是異常處理中經常用到的手段,主要是給函數的調用者拋出異常信息,要求調用的開發人員
對傳遞的數據有一個比較強制的約束
拋出異常:比較常用的手段就是拋出自定義異常
因為系統的某些內建異常,解讀起來還是比較有代溝的!在這樣的情況下,將比較復雜的系統異常
轉換成自定義的信息比較準確的異常數據展示,會更加友好!
4 自定義異常
自定義異常,是根據程序中功能的需要,定義的和項目本身結合比較緊密的個性化的異常信息;自定義異常應用比較廣泛,主要分兩個步驟進行操作
- 定義自定義異常
- 在合適的位置拋出異常
通常情況下,python中的自定義異常,都會選擇從系統標準異常Exception進行繼承實現,如下:
class MyException(Exception):
def __init__(self, message):
self.message = message
def __str__(self):
return “異常描述:%s” % self.message
拋出異常的操作比較簡單,通過關鍵字raise直接拋出異常即可
raise MyException(“出現了自定義異常”)
結合案例:
class MyException(Exception):
‘‘‘
自定義異常
‘‘‘
def __init__(self, msg):
self.msg = msg
def __str__(self):
return "異常描述:%s" % self.msg
# 捕捉異常
try:
# 用戶輸入數據
num1 = float(input("請輸入第一個數據:"))
num2 = float(input("請輸入第二個數據:"))
res = num1 / num2
# 處理類型異常
except ValueError:
print("只能輸入數字")
raise MyException("只能輸入數字,但是用戶輸入了其他非數字字符")
# 處理0除數異常
except ZeroDivisionError:
print("0不能做為除數")
raise MyException("親,不能用0做為除數的")
# 正常結果
else:
# 打印展示結果
print("除法運算結果:%.2f" % res)
finally:
print("計算過程結束")
運行結果:
請輸入第一個數據:q
Traceback (most recent call last):
只能輸入數字
計算過程結束
File "D:/Py1801_B/DATE2/python高級/多線程/text.py", line 30, in <module>
num1 = float(input("請輸入第一個數據:"))
ValueError: could not convert string to float: ‘q‘
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "D:/Py1801_B/DATE2/python高級/多線程/text.py", line 36, in <module>
raise MyException("只能輸入數字,但是用戶輸入了其他非數字字符")
__main__.MyException: 異常描述:只能輸入數字,但是用戶輸入了其他非數字字符
5 python標準異常
異常名稱 | 描述 |
---|---|
BaseException | 所有異常的基類 |
SystemExit | 解釋器請求退出 |
KeyboardInterrupt | 用戶中斷執行(通常是輸入^C) |
Exception | 常規錯誤的基類 |
StopIteration | 叠代器沒有更多的值 |
GeneratorExit | 生成器(generator)發生異常來通知退出 |
StandardError | 所有的內建標準異常的基類 |
ArithmeticError | 所有數值計算錯誤的基類 |
FloatingPointError | 浮點計算錯誤 |
OverflowError | 數值運算超出最大限制 |
ZeroDivisionError | 除(或取模)零 (所有數據類型) |
AssertionError | 斷言語句失敗 |
AttributeError | 對象沒有這個屬性 |
EOFError | 沒有內建輸入,到達EOF 標記 |
EnvironmentError | 操作系統錯誤的基類 |
IOError | 輸入/輸出操作失敗 |
OSError | 操作系統錯誤 |
WindowsError | 系統調用失敗 |
ImportError | 導入模塊/對象失敗 |
LookupError | 無效數據查詢的基類 |
IndexError | 序列中沒有此索引(index) |
KeyError | 映射中沒有這個鍵 |
MemoryError | 內存溢出錯誤(對於Python 解釋器不是致命的) |
NameError | 未聲明/初始化對象 (沒有屬性) |
UnboundLocalError | 訪問未初始化的本地變量 |
ReferenceError | 弱引用(Weak reference)試圖訪問已經垃圾回收了的對象 |
RuntimeError | 一般的運行時錯誤 |
NotImplementedError | 尚未實現的方法 |
SyntaxError | Python 語法錯誤 |
IndentationError | 縮進錯誤 |
TabError | Tab 和空格混用 |
SystemError | 一般的解釋器系統錯誤 |
TypeError | 對類型無效的操作 |
ValueError | 傳入無效的參數 |
UnicodeError | Unicode 相關的錯誤 |
UnicodeDecodeError | Unicode 解碼時的錯誤 |
UnicodeEncodeError | Unicode 編碼時錯誤 |
UnicodeTranslateError | Unicode 轉換時錯誤 |
Warning | 警告的基類 |
DeprecationWarning | 關於被棄用的特征的警告 |
FutureWarning | 關於構造將來語義會有改變的警告 |
OverflowWarning | 舊的關於自動提升為長整型(long)的警告 |
PendingDeprecationWarning | 關於特性將會被廢棄的警告 |
RuntimeWarning | 可疑的運行時行為(runtime behavior)的警告 |
SyntaxWarning | 可疑的語法的警告 |
UserWarning | 用戶代碼生成的警告 |
錯誤和異常處理