- 一. 什么是異常
異常就是程序運行時發生的錯誤,在程序出現錯誤時,則會產生一個異常,若程序沒有處理它,則會拋出該異常,程序的運行也隨之終止,在python中,錯誤觸發的異常如下
錯誤分成兩種:

#語法錯誤示范一 if #語法錯誤示范二 def test: pass #語法錯誤示范三 class Foo pass #語法錯誤示范四 print(haha

#TypeError:int類型不可迭代 for i in 3: pass #ValueError num=input(">>: ") #輸入hello int(num) #NameError aaa #IndexError l=['egon','aa'] l[3] #KeyError dic={'name':'egon'} dic['age'] #AttributeError class Foo:pass Foo.x #ZeroDivisionError:無法完成計算 res1=1/0 res2=1+'str'
- 二. 異常的種類
在python中不同的異常可以用不同的類型(python中統一了類與類型,類型即類)去標識,一個異常標識一種錯誤
1. 常用異常
AttributeError: 試圖訪問一個對象沒有的樹形,比如foo.x,但是foo沒有屬性x IOError: 輸入/輸出異常;基本上是無法打開文件 ImportError: 無法引入模塊或包;基本上是路徑問題或名稱錯誤 IndentationError: 語法錯誤(的子類) ;代碼沒有正確對齊 IndexError: 下標索引超出序列邊界,比如當x只有三個元素,卻試圖訪問x[5] KeyError: 試圖訪問字典里不存在的鍵 KeyboardInterrupt: Ctrl+C被按下 NameError: 使用一個還未被賦予對象的變量 SyntaxError: Python代碼非法,代碼不能編譯(個人認為這是語法錯誤,寫錯了) TypeError: 傳入對象類型與要求的不符合 UnboundLocalError: 試圖訪問一個還未被設置的局部變量,基本上是由於另有一個同名的全局變量,導致你以為正在訪問它 ValueError: 傳入一個調用者不期望的值,即使值的類型是正確的
2.更多異常
ArithmeticError
AssertionError
AttributeError
BaseException
BufferError
BytesWarning
DeprecationWarning
EnvironmentError
EOFError
Exception
FloatingPointError
FutureWarning
GeneratorExit
ImportError
ImportWarning
IndentationError
IndexError
IOError
KeyboardInterrupt
KeyError
LookupError
MemoryError
NameError
NotImplementedError
OSError
OverflowError
PendingDeprecationWarning
ReferenceError
RuntimeError
RuntimeWarning
StandardError
StopIteration
SyntaxError
SyntaxWarning
SystemError
SystemExit
TabError
TypeError
UnboundLocalError
UnicodeDecodeError
UnicodeEncodeError
UnicodeError
UnicodeTranslateError
UnicodeWarning
UserWarning
ValueError
Warning
ZeroDivisionError
- 三.異常處理
為了保證程序的健壯性與容錯性,即在遇到錯誤時程序不會崩潰,我們需要對異常進行處理,
如果錯誤發生的條件是可預知的,我們需要用if進行處理:在錯誤發生之前進行預防
AGE=10 while True: age=input('>>: ').strip() if age.isdigit(): #只有在age為字符串形式的整數時,下列代碼才不會出錯,該條件是可預知的 age=int(age) if age == AGE: print('you got it') break
如果錯誤發生的條件是不可預知的,則需要用到try...except:在錯誤發生之后進行處理
#基本語法為 try: 被檢測的代碼塊 except 異常類型: try中一旦檢測到異常,就執行這個位置的邏輯
#舉例 try: f=open('a.txt') g=(line.strip() for line in f) print(next(g)) print(next(g)) print(next(g)) print(next(g)) print(next(g)) except StopIteration: f.close()
用if處理異常和用try...except 處理異常的區別:
1. if一般處理錯誤的發生條件為可預知的情況;而try...except一般處理錯誤的發生條件不可預知的情況
2. if處理異常會降低代碼的可讀性,對同類型的異常處理會增加重復代碼;而try...except一般可以合並同類型的錯誤進行處理

# 第一段代碼 age=input('>>: ') if age.isdigit(): int(age) #主邏輯 elif age.isspace(): print('---->用戶輸入的空格') elif len(age) == 0: print('----》用戶輸入的為空') else: print('其他的非法輸入') #第二段代碼 num2=input('>>: ') #輸入一個字符串試試 int(num2) if num2.isdigit(): int(num2) #主邏輯 elif num2.isspace(): print('---->用戶輸入的空格') elif len(num2) == 0: print('----》用戶輸入的為空') else: print('其他的非法輸入') # 用if進行處理,合並代碼,但是多個代碼段的合並會越來越長 age = input('>>: ') num2 = input('>>: ') # 輸入一個字符串試試 if age.isdigit() and num2.isdigit() and num3.isdigit() and num4.isdigit() and : int(age) # 主邏輯 int(num2) # 主邏輯 elif age.isspace(): print('---->用戶輸入的空格') elif len(age) == 0: print('----》用戶輸入的為空') else: print('其他的非法輸入')

try: age=input('1>>: ') int(age) # 主邏輯 num2=input('2>>: ') int(num2) # 主邏輯 except ValueError as e: print(e)
異常處理的目的就是程序在運行中出現異常后,不會崩潰,而會有一個其他處理邏輯在等着捕捉該異常,並按照設計邏輯處理掉。
-
- 萬能異常
while True: try: age = input(">>>") int(age) break # 假設try體內有很多主邏輯,可以用下面的方式進行處理,這個叫萬能異常。 # 意思是,不管主邏輯是什么,只要發生異常,都按這一種異常方式進行處理 except Exception as e: print("請重新輸入",e) print("異常處理完了")
那你可能會說,既然有萬能異常,那么我直接用上面這種形式就好了,其他異常類型可以忽略。騷年,你說的沒錯,但是應該分兩種情況:
1. 如果你想要的效果是:無論出現什么異常,都統一丟棄,或者使用同一段代碼邏輯去處理他們,那么大膽的按照萬能異常的方式去處理,只要一個Exception就夠了。
2.如果你想要的效果是:對於不同的異常類型,需要有不同的處理邏輯,那就需要用到多分支了。
多分支意味着有多個Exception,每個Exception后面有一個異常處理邏輯。
s1 = 'hello' s2 = 3` try: int(s1) # 示例里的三個異常分支 except IndexError as e: print(e) except KeyError as e: print(e) except ValueError as e: print(e) # 除了上面三個異常分支外,還可能存在想不到的情況,在加一個萬能異常處理 except Exception as e: print("請重新輸入",e)
-
- 其他的異常結構
else結構 和 finally結構,注意,這兩個是可以單獨存在的
s1 = 'hello' # s1 = 1 try: int(s1) # 示例里的三個異常分支 except IndexError as e: print(e) except KeyError as e: print(e) except ValueError as e: print(e) except Exception as e: print("請重新輸入",e) # else:意味着try內代碼塊沒有異常的時候,會則執行else代碼塊 else: print("try內代碼塊沒有異常,則執行這里") # finally:無論是否存在異常,都會執行該模塊,通常是進行清理工作 finally: print("無論是否存在異常,都要執行該模塊,通常是進行清理工作") print("可能異常的代碼塊之外的代碼邏輯執行了")
-
- 主動觸發異常
try: # 通過raise Python提供的異常類型,加()進行實例化運行,然后傳值進行 raise TypeError("類型錯誤") # 主動觸發的異常也可以被捕捉到的哦 except Exception as e: print("這是主動觸發的異常被捕捉到了",e)
-
- 自定義異常
# 自定義異常 # 異常本身就是類,學完面向對象后,就可以自定義異常類 class MyException(): def __init__(self,message): self.message = message # 自己主動觸發自己的定義的異常 # MyException加()就是在實例化類並運行,那初始化的時候就需要有個變量接這個值。 raise MyException("自己定制的異常") # 報錯 # TypeError: exceptions must derive from BaseException # 意思是自定制的異常必須繼承於 BaseException
自定義異常,必須繼承於BaseException
# 自定義異常 # 異常本身就是類,學完面向對象后,就可以自定義異常類 # 自定義異常,必須繼承BaseException class MyException(BaseException): def __init__(self,message): self.message = message # 自己主動觸發自己的定義的異常 # MyException加()就是在實例化類並運行,那初始化的時候就需要有個變量接這個值。 raise MyException("自己定制的異常")
-
- 斷言:assert
斷言:就是在程序的某個位置判斷是不是你想要的值,如果不是你想要的值,就拋出一個異常,可以用assert做,也可以用if判斷做,只不過if判斷不太好而已。
# 用assert做 def test1(): '一堆邏輯' res = 1 return 1 res1 = test1() assert res1 == 2 # 斷言得知 res1 不等於 2,於是拋出一個AssertionError異常 # AssertionError # 用if判斷做 def test1(): '一堆邏輯' res = 1 return 1 res1 = test1() if res1 != 2: raise AssertionError("斷言異常了") # AssertionError: 斷言異常了 ''' 通過對比發現,assert和if判斷處理的結果是一樣的,但是代碼量上,assert一行代碼解決了if判斷2行的代碼,所以建議用assert進行斷言處理 '''
try...excepe方式比較if的方式的好處
try...excepte這種異常處理機制就是取代if那種方式的,讓你的程序在不犧牲可讀性的前提下增強健壯性,異常處理中為每一個異常定制了異常類型(Python中統一了類與類型,類型即類),對於同一種異常,一個except 就可以捕捉到,可以同時處理多段代碼的異常(無需再寫多個if判斷)減少了代碼,增強了可讀性。
使用try...except方式的好處:
1. 把錯誤處理和真正的工作分開了
2. 代碼更易組織,更清晰,復雜的工作任務更容易實現
3. 毫無疑問,更安全了,不至於由於一些小的疏忽而使程序意外崩潰了。
注意:
if 也可以進行異常處理,只不過用try...except進行異常處理,能夠獲得if無法實現的好處。
- 四.什么時候用異常處理?
學完了異常處理后,好強大,我要為我的每一段程序都加上try...except,干毛線去思考它會不會有邏輯錯誤啊,這樣就很好啊,多省腦細胞===》2B青年歡樂多,擦,我就是這么想的。算了,還是當個正常青年吧。
首先try...except是你附加給你的程序的一種異常處理的邏輯,與你的主要的工作是沒有關系的,這種東西加的多了,會導致你的代碼可讀性變差;
然后異常處理本就不是你2b邏輯的擦屁股紙,只有在錯誤發生的條件無法預知的情況下,才應該加上try...except,所以要盡量修正代碼的邏輯,少用try...except。