1、異常 Exception
錯誤Error
邏輯錯誤:算法寫錯了,加法寫成了減法。
筆誤:變量名寫錯了,語法錯誤。
錯誤可以避免的
異常Exception
本身就是意外情況。一些意外,導致程序無法正常的執行下去。
是不可避免的。
錯誤和異常
在高級編程語言中,一般都有錯誤和異常的概念,異常是可以捕獲的並被處理的,但是錯誤是不能捕獲的。
with open('test') as f:
pass
錯誤信息:
Traceback (most recent call last):
File "C:/Users/WCL/PycharmProjects/untitled1/package/test1/異常處理.py", line 1, in <module>
with open('test') as f:
FileNotFoundError: [Errno 2] No such file or directory: 'test'
def 0A():
pass
File "C:/Users/WCL/PycharmProjects/untitled1/package/test1/參數檢查.py", line 142
class typeassert
^
SyntaxError: invalid syntax
一個健壯的程序,盡可能的避免錯誤。
盡可能的捕獲,處理各種異常。
2、產生異常
產生:raise語句顯示的拋出異常。
Python解釋器自己檢測到異常並引發他。
def foo():
print('-----')
def bar():
print(1/0)
bar()
print('after')
foo()
def bar():
print('+++++++++++++')
raise Exception('Exc')
print('+-+-+-+-+-+')
bar()
程序會在異常拋出的地方中斷執行,如果不進行捕獲,就會提前結束程序。
raise語句
raise后什么都沒有,表示拋出最近一個被激活的異常,如果沒有被激活的異常,則拋出類型異常。很少利用的方式。
raise
后要求應該是BaseException類的子類或實例,如果是類,將被無參實例化。
異常必須出自BaseException
sys.exc_info()查看異常所在的元素。
sys.exc_info() ,后面是個元組。(異常類、異常對象,trackback)
3、異常捕獲
try:
待捕獲異常的代碼塊
except[異常類型]:
異常的處理代碼塊
try:
print('++++++++++++++++')
c = 1/0
print('----------------')
except:
print('catch the exception')
print('outer')
++++++++++++++++
catch the exception
Outer
執行到c = 1/0時候產生異常並拋出,由於使用了語句捕捉這個異常,所以產生異常位置后面的語句將不再執行了,轉而執行對象except以外的語句。
2)捕獲指定類型的異常。
try:
print('++++++++++++++++')
c = 1/0
print('----------------')
except ArithmeticError:
print('catch the ArithmeticError:')
print('outer')
++++++++++++++++
catch the ArithmeticError:
Outer
特別關心的異常放在最上面。
自己定義的異常。
Exception 非退出性異常。
捕獲原則:
4、異常類即繼承層次
def exc_hierarchy(exc=BaseException, level=-1):
name = exc.__name__
if level == -1:
print(name)
else:
print("{} +-- {}".format(' ' * level, name))
for sub in exc.__subclasses__():
exc_hierarchy(sub, level+1)
BaseException
+-- Exception
+-- StopAsyncIteration
+-- OSError
+-- BlockingIOError
+-- FileNotFoundError
+-- IsADirectoryError
+-- TimeoutError
+-- InterruptedError
+-- ProcessLookupError
+-- NotADirectoryError
+-- ConnectionError
+-- BrokenPipeError
+-- ConnectionAbortedError
+-- ConnectionRefusedError
+-- ConnectionResetError
+-- UnsupportedOperation
+-- FileExistsError
+-- ChildProcessError
+-- PermissionError
+-- ArithmeticError
+-- FloatingPointError
+-- OverflowError
+-- ZeroDivisionError
+-- AttributeError
+-- SyntaxError
+-- IndentationError
+-- TabError
+-- SystemError
+-- CodecRegistryError
+-- ImportError
+-- ZipImportError
+-- BufferError
+-- LookupError
+-- IndexError
+-- KeyError
+-- CodecRegistryError
+-- NameError
+-- UnboundLocalError
+-- TypeError
+-- error
+-- StopIteration
+-- AssertionError
+-- Warning
+-- UserWarning
+-- DeprecationWarning
+-- UnicodeWarning
+-- PendingDeprecationWarning
+-- ImportWarning
+-- RuntimeWarning
+-- ResourceWarning
+-- SyntaxWarning
+-- BytesWarning
+-- FutureWarning
+-- Error
+-- ValueError
+-- UnicodeError
+-- UnicodeEncodeError
+-- UnicodeDecodeError
+-- UnicodeTranslateError
+-- UnsupportedOperation
+-- ReferenceError
+-- RuntimeError
+-- RecursionError
+-- NotImplementedError
+-- _DeadlockError
+-- MemoryError
+-- EOFError
+-- GeneratorExit
+-- KeyboardInterrupt
+-- SystemExit
5、BaseException及子類
1)BaseException所有內建異常類的基類是BaseException。
2)SystemExit
sys.exit()函數引發的異常,異常不捕獲處理,就直接交給Python解釋器,解釋器退出。
import sys
print('++++')
sys.exit(1)
print('sysexit')
print('-----')
++++
Process finished with exit code 1
未進行捕獲的情況下,
解釋器直接退出了。
import sys
try:
print('++++')
sys.exit(1)
except SystemExit:
print('sysexit')
print('-----')
++++
sysexit
-----
捕獲的情況下正常執行,且被捕獲。
3)Keyboardinterrupt
對應捕獲用戶中斷的行為 Ctrl + c
6、Exception及子類
Exception是所有內建的,非系統退出的異常的基類,自定義異常應該定義繼承自它。
1)SyntaxError語法錯誤,Python中也歸到Exception類中,但是語法錯誤是不可被捕獲的。
2)ArithmeticError所有算數計算引發的異常,其子類有除零異常等。
3)LookupError 使用映射的鍵或者序列的索引無效是引發的異常的基類:indexerror keyerror
4)自定義的異常:從Exception繼承的類。
7、異常的捕獲
Except可以捕獲多個異常。
捕獲的原則:捕獲是從上到下依次比較,如果匹配,則執行匹配的except語句塊。
如果被一個except語句塊捕獲,其他的except就不會再次捕獲了。
如果沒有任何一個except語句捕獲到這個異常,則該異常向外拋出。
捕獲的原則,從小到大,從具體到廣泛。
8、as子句
被拋出的異常,應該是異常的實例,獲得這個對象的話,使用as子句。
class MyException(Exception):
def __init__(self,code,message):
self.code = code
self.message = message
try:
raise MyException
except MyException as e:
print(11111111)
print('{}{}'.format(e.code,e.message))
except Exception as e:
print('{}'.format(e))
__init__() missing 2 required positional arguments: 'code' and 'message'
raise后面有特定的參數,如果沒有的話就是無參形式。
9、finally 子句
Finally 最終,即最后都會是要一定執行的。try.....finally不管有沒有異常都會執行。
Finally中一般都是放置資源的清理,釋放工作的語句。
也可以在finally中再次捕獲異常。
10、finally執行時機
def foo():
try:
return 3
finally:
print('finally')
print('---')
print(foo())
盡管函數有return返回語句,但是finally語句還是要執行的,最后才返回return語句。
拿的值是最后一個return。
11、異常傳遞
def foo1():
return 1/0
def foo2():
print('foo2 ----')
foo1()
print('foo2++++')
foo2()
foo2調用了foo1,foo1產生的異常傳遞到了foo2中
異常總是向外層拋出,如果外層沒有處理這個異常,就會繼續向外拋出,如果內層捕獲並處理了異常,外部就不能捕獲的到了。
如果到了最外層還是沒有被處理,就會中斷異常所在的線程的執行。
import threading
import time
def foo1():
return 1/0
def foo2():
time.sleep(3)
print('foo2----')
foo1()
print('foo2++++')
t = threading.Thread(target=foo2)
t.start()
while True:
time.sleep(1)
print('Everything OK')
if t.is_alive():
print('live')
else:
print('dead')
未進行捕獲異常,異常拋出直接中斷了線程。
sys.exc_info() ,后面是個元組。(異常類、異常對象,trackback)
12、try 的嵌套
try:
try:
ret = 1/0
except KeyError as k:
print(k)
else:
print('ok')
finally:
print('finally')
except:
print('c ok')
finally:
print('fin')
內部捕獲不到異常,會向外層傳遞異常。
但是如果內層有且有finally而且其中有return、break語句,否則就不會繼續往外拋出異常。
def foo():
try:
ret = 1/0
except KeyError as F:
print(k)
finally:
print('finally a ')
return #異常直接被丟棄
try:
foo()
except:
print('+++++')
finally:
print('-------')
有return語句,異常直接被丟棄。
13、異常的捕獲時機
1)立即捕獲
需要立即返回一個明確的結果
def parse_int(s):
try:
return int(s)
except:
return 0
print(parse_int('s'))
被return直接返回0
2)邊界捕獲
封裝產生了邊界。
(1)一個模塊,用戶調用了這個模塊的時候捕獲異常,異常內部不需要捕獲,處理異常,一旦內部處理了,外部調用者無法感知異常了
(2)Open函數,出現的異常交給調用者處理,文件存在,就不用創建了,看是否修改修改還是刪除。
(3)自己寫了一個類,使用open函數,但是文件出現異常不知道如何處理,就繼續向外層拋出,一般來說最外層也是邊界,必須處理異常,如果不處理的話,線程就會推出。
14、else子句
else子句,沒有異常發生,則執行。
try:
ret = 1/0
except ArithmeticError as e:
print(e)
else:
print('ok')
finally:
print('fin')
####division by zero
###fin
15、總結
try:
<語句> #運行別的代碼
except<異常類>:
<語句> #捕獲某種類型的異常
except<異常類> as <變量名>:
<語句> #捕獲某種類型的異常並獲得對象
else:
<語句> #如果沒有異常發生
finally:
<語句> #推出try的時候總會執行
try的工作原理
(1)如果try中語句執行時候會發生異常,搜索except子句,並執行第一個匹配該異常的except子句。
(2)如果try中語句執行時發生異常,卻沒有匹配except子句,異常將被遞交到外層的try,如果外層不處理這個異常,異常將繼續向外層傳遞,如果都不處理該異常,則會傳遞到最外層,如果還沒有處理,就會終止異常所在的線程。
(3)如果try執行時候沒有異常,將執行else子句中的語句。
(4)無論try中是否發生異常,finally子句最終都會執行。
