返回目錄html
本篇索引python
(1)內置異常緩存
(2)自定義異常網絡
(3)主動引起異常app
(4)捕捉異常異步
(5)error模塊函數
(6)with語句oop
● 異常的基類:ui
如下這些異常做爲具體異常的基類,都不會被顯式引起,可是可使用它們捕捉某種錯誤。編碼
基類名稱 | 說明 | ||
---|---|---|---|
BaseException | 全部內置異常的基類,其餘全部內置異常都派生自該類。 |
||
Exception | 全部內置的非系統退出異常都派生自此類(即除了:SystemExit, GeneratorExit, KeyboardInterrupt以外的全部內置異常)。全部用戶自定義異常也應當派生自此類。 | ||
ArithmeticError | 算術運算異常的基類,包括溢出、除零等等。 | ||
LookupError | 索引和鍵錯誤的基類。 | ||
BufferError | 當與緩衝區相關的操做沒法執行時引起,通常由用戶自行繼承使用。 |
● 具體異常
如下異常屬於常常被引起的異常。
具體異常名稱 | 說明 |
---|---|
如下異常直接繼承自:BaseException | |
GeneratorExit | 由生成器的.close()方法引起。 |
KeyboardInterrupt | 由鍵盤中斷(一般爲 Ctrl-C)生成。 |
SystemExit | 程序退出,通常系統函數sys.exit()引起。 |
如下異常繼承自:BaseException -> Exception | |
StopIteration | 引起後可中止迭代。 |
StopAsyncIteration | 由異步迭代器引起中止迭代。 |
AssertionError | 當 assert 語句失敗時引起。 |
AttributeError | 當屬性引用或屬性賦值失敗時引起。 |
EOFError | 當 input() 函數未讀取任何數據即達到文件結束條件 (EOF) 時將被引起。(文件操做的諸如read()和readline()方法等I/O操做在遇到EOF時會返回空字符串,而不是引起異常) |
ImportError | 當 import 語句沒法找到模塊或者 from 沒法在模塊中找到名稱時引起。Python3.3版本後,對此異常添加了name和path屬性,用來表示「嘗試導入的模塊名稱」和「觸發異常的文件所在的路徑」。 |
ModuleNotFoundError | ImportError的子類,Python3.6版本新加入。當一個模塊沒法找到時由import引起。 |
MemoryError | 可用內存不足(但仍可挽救時)時將被引起。 |
NameError | 在局部或全局命名空間中未找到某個名稱時引起。 |
UnboundLocalError | NameError的子類。引用了未綁定的局部變量時引起。 |
OSError | Python3.3起,如下都是OSError的別名:IOError、EnvironmentError、WindowsError(僅限Windows中)。 操做系統錯誤,主要由os模塊中的函數引發。 |
BlockingIOError | OSError的子類。當一個操做阻塞一個設置爲非阻塞操做的對象時引起。 |
ChildProcessError | OSError的子類。當對子進程進行操做失敗時將引起,對應於Linux系統調用時的errno中的 ECHILD |
ConnectionError | 與鏈接相關問題的基類。 |
BrokenPipeError | ConnectionError的子類。當試圖寫入另外一端已被關閉的管道,或是試圖寫入已關閉寫入的套接字時引起。對應於Linux系統調用時的errno中的 EPIPE 和 ESHUTDOWN。 |
ConnectionAbortedError | ConnectionError的子類。當鏈接嘗試被對端停止時將被引起。對應於Linux系統調用時的errno中的 ECONNABORTED。 |
ConnectionRefusedError | ConnectionError的子類。當鏈接嘗試被對端拒絕時將被引起。對應於Linux系統調用時的errno中的 ECONNREFUSED。 |
ConnectionResetError | ConnectionError的子類。當鏈接被對端重置時將被引起。對應於Linux系統調用時的errno中的 ECONNRESET。 |
FileExistsError | OSError的子類。當試圖建立一個已存在的文件或目錄時將被引起。對應於Linux系統調用時的errno中的 EEXIST。 |
FileNotFoundError | OSError的子類。當所請求的文件或目錄不存在時引起。對應於Linux系統調用時的errno中的 ENOENT。 |
InterruptedError | OSError的子類。當系統調用被輸入信號中斷時引起。對應於Linux系統調用時的errno中的 EINTR。 |
IsADirectoryError | OSError的子類。當請求對一個目錄執行文件操做時引起。對應於Linux系統調用時的errno中的 EISDIR。 |
NotADirectoryError | OSError的子類。當請求對一個非目錄對象執行目錄操做時引起。對應於Linux系統調用時的errno中的 ENOTDIR。 |
PermissionError | OSError的子類。當沒有對相應文件操做權限的時候引起。對應於Linux系統調用時的errno中的 EACCESS和 EPERM |
ProcessLookupError | OSError的子類。當給定的進程不存在時引起。對應於Linux系統調用時的errno中的 ESRCH。 |
TimeoutError | OSError的子類。當一個系統函數發生系統級超時的狀況下將被引起。對應於Linux系統調用時的errno中的 ETIMEDOUT。 |
ReferenceError | 在弱引用訪問某個已被垃圾回收的屬性時引起,關於弱引用可參見werkref模塊。 |
RuntimeError | 當檢測到一個不屬於任何其餘類別的錯誤時引起。 |
NotImplementedError | RuntimeError的子類。當基類的抽象方法須要派生類實現,而派生類未實現時引起。 |
RecursionError | RuntimeError的子類。Python解釋器檢測發現超過最大遞歸深度時引起。 |
SyntaxError | 解析器語法錯誤。 |
IndentationError | SyntaxError的子類。縮進錯誤時引起。 |
TabError | IndentationError的子類。當縮進包含對製表符和空格符不一致的使用時引起。 |
SystemError | Python解釋器中的內部錯誤。 |
TypeError | 當一個操做或函數被應用於類型不適當的對象時引起。 |
ValueError | 當操做或函數接收到具備正確類型但值不適合的參數時引起。 |
UnicodeError | ValueError的子類。Unicode編碼或解碼錯誤時引起。 |
UnicodeEncodeError | UnicodeError的子類。Unicode編碼錯誤。 |
UnicodeDecodeError | UnicodeError的子類。Unicode解碼錯誤。 |
UnicodeTranslateError | UnicodeError的子類。在轉換過程當中產生的與Unicode相關的錯誤。 |
如下異常繼承自:BaseException -> Exception -> ArithmeticError | |
FloatingPointError | 目前未被使用。 |
OverflowError | 當一個運算結果大到沒法表示時將被引起。 |
ZeroDivisionError | 當除法或取餘運算的第二個參數爲零時將被引起。 |
如下異常繼承自:BaseException -> Exception -> LookupError | |
IndexError | 序列的下標超出範圍時引起。 |
KeyError | 映射(字典)中未找到鍵時引起。 |
如下警告繼承自:BaseException -> Exception -> Warning | |
DeprecationWarning | 與已棄用特性相關警告的基類。 |
PendingDeprecationWarning | 對於已過期並預計在將來棄用,但目前還沒有棄用的特性相關警告的基類。 |
RuntimeWarning | 與模糊的運行時行爲相關的警告的基類。 |
SyntaxWarning | 與模糊的語法相關的警告的基類。 |
UserWarning | 用戶代碼所產生警告的基類。 |
FutureWarning | 與已棄用特性相關警告的基類。 |
ImportWarning | 與在模塊導入中可能的錯誤相關的警告的基類。 |
UnicodeWarning | 與 Unicode 相關的警告的基類。 |
BytesWarning | 與 bytes 和 bytearray 相關的警告的基類。 |
ResourceWarning | 與資源使用相關的警告的基類。 會被默認的警告過濾器忽略。 |
能夠經過繼承Exceptions類而定義本身的異常。定義完以後,可使用raise語句引起這個新的異常,以下例所示:
class NetworkError(Exception): pass raise NetworkError('Cannot find host')
下例顯示瞭如何在自定義異常中帶有多個異常值:
class NetworkError(Exception): def __init__(self, errno, msg): self.args = (errno, msg) # 賦值給args是必須的,不然用戶沒法看到自定義異常的任何細節提示信息 self.errno = errno self.msg = msg raise NetworkError(1, 'No response')
使用繼承機制將異常組成一個層次結構:
class NetworkError(Exception): pass class HostnameError(NetworkError): pass class TimeoutError(NetworkError): pass # 如下爲引起並捕捉自定義異常 try: raise TimeoutError('Time out') except NetworkError as e: if type(e) is TimeoutError: pass
● Assert(斷言)
斷言的基本目的是:與其讓程序在在未來不知某個時候崩潰,不如在程序中不符合某個預判條件時,主動讓程序崩潰。 當斷言條件不知足時,會引起AssertionError異常。assert的格式爲:
assert condition [,msg]
其中,condition是一個表達式,其值若爲False時,assert語句就會引起AssertionError異常。 能夠在assert語句後添加字符串msg,用來在發生異常時,提示預先設置的字符串信息。
使用舉例:
age = -1 assert 0 < age < 100 'The age is fantastic.' # 執行本句時,會引起AssertionError異常,並會提示:The age is fantastic.
assert語句常和 if __debug__語句一塊兒使用。在調試模式中,只讀變量__debug__的值爲True,能夠隨意地在代碼中加入assert和調試檢查。 在最優模式中(經過-O指定),__debug__爲False,將省略全部這些額外的檢查。
● raise
使用raise語句可主動引起異常,raise語句的格式爲:
raise Exception([value])
若是raise語句沒有帶任何參數,將會再次引起最近一次生成的異常。
raise使用舉例:
raise KeyError('abc') # 引起KeyError異常,並提示字符串 'abc'
一般,使用捕捉異常的代碼結構要比使用多個if-else語句判斷來得更清晰,並且執行效率也幾乎沒什麼損失,故應該在程序中儘量使用try/except語句來查錯。 通常except語句捕捉並處理完異常後,程序將繼續執行跟在最後一個except代碼塊中的語句,程序並不會返回發生異常時的位置。
若是異常在函數內引起而未被處理,它就會向上傳遞到函數調用的地方,若是在那裏也沒有被處理,就會繼續向上傳遞,直到主程序(全局做用域)。 若是主程序裏也沒有處理,程序會帶着堆棧跟蹤中止。
若是須要,也能夠把未捕捉的異常傳遞給用戶自定義的函數sys.excepthook()進行處理。
● try-except結構:
捕捉單個異常:
try: x = 2/0 except ZeroDivisionError: print 'The divisor is zero'
捕捉多個異常:
# 方法一: try: x = 2/'a' except ZeroDivisionError: pass except TypeError: pass # 方法二: try: x = 2/'a' except (ZeroDivisionError, TypeError, NameError): print('oops!')
捕捉全部異常:
try: x = 2/0 except Exception: # 這裏使用基類Exception可捕捉除了「鍵盤中斷」和「程序退出」的全部異常 pass
捕捉異常並訪問異常對象:
try: x = 2/0 except Exception as e: print(e)
這裏生成的異常實例e具備一些標準屬性,列舉以下:
e.args:引起異常時提供的參數元組,通常包含有描述該錯誤的字符串。
e.__cause__:使用顯式關聯異常時的前一個異常。
e.__context__:使用隱式關聯異常時的前一個異常。
e.__traceback__:與異常相關的跟蹤對象。
● try-except-else結構
當try中的語句沒有發生異常請跨下,運行else語句塊中內容。
示例:
try: f = open('foo', 'r') except IOError as e: print(e) else: data = f.read() f.close()
● try-except-finally結構
finally語句塊用於不管try是否有異常,都要運行的代碼。若是沒有引起異常,finally子句中的代碼將在try的代碼塊執行完後當即執行。 若是捕捉到了異常,則finally中的內容先運行,而後再運行except語句塊中的內容。
示例:
try: f = open('foo', 'r') data = f.read() except IOError as e: print(e) finally: f.close() # 不管前面發生什麼,都會關閉文件
● try-except-else-finally結構
else和finally也能夠組合在一塊兒使用。
示例:
try: f = open('foo', 'r') except IOError as e: print(e) else: data = f.read() finally: f.close()
errno模塊爲各類操做系統調用返回的整數錯誤代碼定義了符號名稱,這些整數代碼一般可在OSError(別名IOError)異常的errno屬性中找到。
os.strerror()函數能夠將整數的錯誤代碼轉換爲字符串信息。
errno模塊的errorcode字典,記錄了當前操做系統支持的錯誤代碼和POSIX符號名稱的對應關係,下表列舉了部分經常使用的錯誤代碼。
OSError中的錯誤代碼信息:
try: f = open(r'xxxxxx', 'r') except Exception as e: print(e.errno) print(e.args) # 運行結果爲: 2 (2, 'No such file or directory')
os.strerror()使用示例:
import os import errno print(os.strerror(2)) # 運行結果爲錯誤代碼2的字符串含義:No such file or directory'
● 常見POSIX錯誤代碼
錯誤代碼 | 名稱 | 描述 |
---|---|---|
1 | EPERM | 操做未獲得許可 |
2 | ENOENT | 文件或目錄不存在 |
3 | ESRCH | 進程不存在 |
4 | EINTR | 系統調用被中斷 |
5 | EIO | I/O錯誤 |
6 | ENXIO | 設備或地址不存在 |
7 | E2BIG | 參數列表過長 |
8 | ENOEXEC | 訪問被拒絕 |
9 | EBADF | 錯誤的文件編號 |
10 | ECHILD | 無子進程 |
11 | EAGAIN | 再試 |
12 | ENOMEM | 內存不足 |
13 | EACCESS | 訪問被拒絕 |
14 | EFAULT | 錯誤的地址 |
15 | ENOTBLK | 須要塊設備 |
16 | EBUSY | 設備或資源方面 |
17 | EEXIST | 文件存在 |
18 | EXDEV | 跨設備連接 |
19 | ENODEV | 沒有這個設備 |
20 | ENOTDIR | 不是一個目錄 |
21 | EISDIR | 是一個目錄 |
22 | EINVAL | 無效參數 |
23 | ENFILE | 文件表溢出 |
24 | EMFILE | 打開文件過多 |
25 | ENOTTY | 不是一個終端 |
26 | ETXTBSY | 文本文件忙 |
27 | EFBIG | 文件過大 |
28 | ENOSPC | 設備上無剩餘空間 |
29 | ESPIPE | 非法尋址 |
30 | EROFS | 只讀文件系統 |
31 | EMLINK | 連接過多 |
32 | EPIPE | 管道已損壞 |
33 | EDOM | 數學參數在函數做用域以外 |
34 | ERANGE | 沒法表示的數學結果 |
35 | EDEADLOCK | 文件鎖定死鎖錯誤 |
36 | ENAMETOOLONG | 文件名過長 |
37 | ENOLCK | 無可用記錄鎖定 |
38 | ENOSYS | 函數沒法實現 |
39 | ENOTEMPTY | 目錄不爲空 |
40 | ELOOP | 遇到過多的符號連接 |
84 | EILSEQ | 非法的字節序列 |
85 | ERESTART | 中斷系統調用需重啓 |
86 | ESTRPIPE | 流管道錯誤 |
87 | EUSERS | 用戶過多 |
88 | ENOTSOCK | 非套接字上的套接字操做 |
89 | EDESTADDRREQ | 須要目的地址 |
90 | EMSGSIZE | 消息過長 |
91 | EPROTOTYPE | 套接字的協議類型錯誤 |
92 | ENOPROTOOPT | 協議不可用 |
93 | EPROTONOSUPPORT | 不支持協議 |
94 | ESOCKTNOSUPPORT | 套接字類型不受支持 |
95 | ENOTSUP | 操做被遠端支持 |
96 | EPFNOSUPPORT | 不支持協議族 |
97 | EAFNOSUPPORT | 協議不支持地址族 |
98 | EADDRINUSE | 地址已使用 |
99 | EADDRNOTAVAIL | 沒法分配請求的地址 |
100 | ENETDOWN | 網絡已關閉 |
101 | ENETUNREACH | 網絡不可到達 |
102 | ENETRESET | 網絡因爲重置中斷鏈接 |
103 | ECONNABORTED | 軟件致使鏈接中斷 |
104 | ECONNRESET | 對等端已將鏈接重置 |
105 | ENOBUFS | 無可用緩存空間 |
106 | EISCONN | 傳輸端點已經鏈接 |
107 | ENOTCONN | 傳輸端點未鏈接 |
108 | ESHUTDOWN | 沒法在傳輸端點關閉後發送 |
109 | ETOOMANYREFS | 引用過多:沒法鏈接 |
110 | ETIMEDOUT | 鏈接超時 |
111 | ECONNREFUSED | 鏈接被拒絕 |
112 | EHOSTDOWN | 主機已關閉 |
113 | EHOSTUNREACH | 無路由通向主機 |
114 | EALREADY | 操做已經在進行中 |
115 | EINPROGRESS | 操做正在進行 |
116 | ESTALE | 失效的NFS文件句柄 |
125 | ECANCELED | 操做取消 |
126 | ENOKEY | 無此鍵 |
127 | EKEYEXPIRED | 鍵過時 |
128 | EKEYREVOKED | 鍵被撤回 |
129 | EKEYREJECTED | 鍵被服務拒絕 |
130 | EOWNERDEAD | 擁有者已不存在 |
131 | ENOTRECOVERABLE | 狀態不可恢復 |
132 | ERFKILL | 操做因爲RF-KILL沒法進行 |
with語句支持在「上下文管理器」對象的控制下,執行一系列語句。經常使用於管理各類系統資源(如文件、鎖、鏈接等)。 當程序中發生異常,而致使脫離正常的釋放資源語句時,只要用了with,就能夠保證在離開with語句塊時自動釋放這些資源。下面是2個簡單的例子:
自動關閉文件對象
with open('a.txt', 'w') as f: f.write('xyz\n') ...... f.write('done\n') # 當程序離開with語句塊時,with語句會自動關閉已打開的文件
自動釋放鎖
import threading lock = threading.Lock() with lock: ...... # 當程序離開with語句塊時,with語句會自動釋放這個鎖
● with語句的通常語法:
with obj [as var] statements
obj對象須要實現__enter__()方法和__exit__()方法來支持with語句。當執行with obj語句時,會自動調用obj.__enter__()方法, 該方法的返回值將被放入指定變量var中。
當程序離開with語句塊時,會自動調用obj.__exit__()方法,其入參形式爲:__exit__(type, value, traceback), 三個入參分別爲:當前異常的類型、值、跟蹤信息。__exit__()方法返回True或False(表示被引起的異常是否獲得了處理)
如下爲一個用戶自定義類支持with的例子,這個類支持對已有列表進行一系列修改, 但這些修改只有在沒有發生異常時纔會生效,不然原始列表將保持不變。
class ListTransaction(object): def __init__(self, thelist): self.thelist = thelist def __enter__(self): self.workingcopy = list(self.thelist) return self.workingcopy def __exit__(self, type, value, tb): if type is None: self.thelist[:] = self.workingcopy return # 使用with語句: items = [1,2,3] try: with ListTransaction(items) as working: working.append(4) working.append(5) raise RuntimeError() except RuntimeError: pass print(items) # 因爲在離開with語句塊時發生了異常,所以__exit__()的入參type不爲None,最終結果爲:[1,2,3]