Python基础之:Python中的异常和错误
文章目錄
- 簡介
- Python中的內置異常類
- 語法錯誤
- 異常
- 異常處理
- 拋出異常
- 異常鏈
- 自定義異常
- finally
簡介
和其他的語言一樣,Python中也有異常和錯誤。在 Python 中,所有異常都是 BaseException 的類的實例。 今天我們來詳細看一下Python中的異常和對他們的處理方式。
Python中的內置異常類
Python中所有異常類都來自BaseException,它是所有內置異常的基類。
雖然它是所有異常類的基類,但是對于用戶自定義的類來說,并不推薦直接繼承BaseException,而是繼承Exception.
先看下Python中異常類的結構關系:
BaseException+-- SystemExit+-- KeyboardInterrupt+-- GeneratorExit+-- Exception+-- StopIteration+-- StopAsyncIteration+-- ArithmeticError| +-- FloatingPointError| +-- OverflowError| +-- ZeroDivisionError+-- AssertionError+-- AttributeError+-- BufferError+-- EOFError+-- ImportError| +-- ModuleNotFoundError+-- LookupError| +-- IndexError| +-- KeyError+-- MemoryError+-- NameError| +-- UnboundLocalError+-- OSError| +-- BlockingIOError| +-- ChildProcessError| +-- ConnectionError| | +-- BrokenPipeError| | +-- ConnectionAbortedError| | +-- ConnectionRefusedError| | +-- ConnectionResetError| +-- FileExistsError| +-- FileNotFoundError| +-- InterruptedError| +-- IsADirectoryError| +-- NotADirectoryError| +-- PermissionError| +-- ProcessLookupError| +-- TimeoutError+-- ReferenceError+-- RuntimeError| +-- NotImplementedError| +-- RecursionError+-- SyntaxError| +-- IndentationError| +-- TabError+-- SystemError+-- TypeError+-- ValueError| +-- UnicodeError| +-- UnicodeDecodeError| +-- UnicodeEncodeError| +-- UnicodeTranslateError+-- Warning+-- DeprecationWarning+-- PendingDeprecationWarning+-- RuntimeWarning+-- SyntaxWarning+-- UserWarning+-- FutureWarning+-- ImportWarning+-- UnicodeWarning+-- BytesWarning+-- ResourceWarning其中BaseException,Exception,ArithmeticError,BufferError,LookupError 主要被作為其他異常的基類。
語法錯誤
在Python中,對于異常和錯誤通常可以分為兩類,第一類是語法錯誤,又稱解析錯誤。也就是代碼還沒有開始運行,就發生的錯誤。
其產生的原因就是編寫的代碼不符合Python的語言規范:
>>> while True print('Hello world')File "<stdin>", line 1while True print('Hello world')^ SyntaxError: invalid syntax上面代碼原因是 print 前面少了 冒號。
異常
即使我們的程序符合python的語法規范,但是在執行的時候,仍然可能發送錯誤,這種在運行時發送的錯誤,叫做異常。
看一下下面的異常:
>>> 10 * (1/0) Traceback (most recent call last):File "<stdin>", line 1, in <module> ZeroDivisionError: division by zero >>> 4 + spam*3 Traceback (most recent call last):File "<stdin>", line 1, in <module> NameError: name 'spam' is not defined >>> '2' + 2 Traceback (most recent call last):File "<stdin>", line 1, in <module> TypeError: Can't convert 'int' object to str implicitly異常處理
程序發生了異常之后該怎么處理呢?
我們可以使用try except 語句來捕獲特定的異常。
>>> while True: ... try: ... x = int(input("Please enter a number: ")) ... break ... except ValueError: ... print("Oops! That was no valid number. Try again...") ...上面代碼的執行流程是,首先執行try中的子語句,如果沒有異常發生,那么就會跳過except,并完成try語句的執行。
如果try中的子語句中發生了異常,那么將會跳過try子句中的后面部分,進行except的異常匹配。如果匹配成功的話,就會去執行except中的子語句。
如果發生的異常和 except 子句中指定的異常不匹配,則將其傳遞到外部的 try語句中。
一個try中可以有多個except 子句,我們可以這樣寫:
try:raise cls()except D:print("D")except C:print("C")except B:print("B")一個except也可以帶多個異常:
... except (RuntimeError, TypeError, NameError): ... passexcept 子句還可以省略異常名,用來匹配所有的異常:
import systry:f = open('myfile.txt')s = f.readline()i = int(s.strip()) except OSError as err:print("OS error: {0}".format(err)) except ValueError:print("Could not convert data to an integer.") except:print("Unexpected error:", sys.exc_info()[0])raisetry … except語句有一個可選的 else 子句,在使用時必須放在所有的 except 子句后面。對于在 try 子句不引發異常時必須執行的代碼來說很有用。 例如:
for arg in sys.argv[1:]:try:f = open(arg, 'r')except OSError:print('cannot open', arg)else:print(arg, 'has', len(f.readlines()), 'lines')f.close()except可以指定異常變量的名字 instance ,這個變量代表這個異常實例。
我們可以通過instance.args來輸出異常的參數。
同時,因為異常實例定義了 __str__(),所以可以直接使用print來輸出異常的參數。而不需要使用 .args。
我們看一個例子:
>>> try: ... raise Exception('spam', 'eggs') ... except Exception as inst: ... print(type(inst)) # the exception instance ... print(inst.args) # arguments stored in .args ... print(inst) # __str__ allows args to be printed directly, ... # but may be overridden in exception subclasses ... x, y = inst.args # unpack args ... print('x =', x) ... print('y =', y) ... <class 'Exception'> ('spam', 'eggs') ('spam', 'eggs') x = spam y = eggs上面的例子中,我們在try字句中拋出了一個異常,并且指定了2個參數。
拋出異常
我們可以使用raise語句來拋出異常。
>>> raise NameError('HiThere') Traceback (most recent call last):File "<stdin>", line 1, in <module> NameError: HiThereraise的參數是一個異常,這個異常可以是異常實例或者是一個異常類。
注意,這個異常類必須是Exception的子類。
如果傳遞的是一個異常類,那么將會調用無參構造函數來隱式實例化:
raise ValueError # shorthand for 'raise ValueError()'如果我們捕獲了某些異常,但是又不想去處理,那么可以在except語句中使用raise,重新拋出異常。
>>> try: ... raise NameError('HiThere') ... except NameError: ... print('An exception flew by!') ... raise ... An exception flew by! Traceback (most recent call last):File "<stdin>", line 2, in <module> NameError: HiThere異常鏈
如果我們通過except捕獲一個異常A之后,可以通過raise語句再次拋出一個不同的異常類型B。
那么我們看到的這個異常信息就是B的信息。但是我們并不知道這個異常B是從哪里來的,這時候,我們就可以用到異常鏈。
異常鏈就是拋出異常的時候,使用raise from語句:
>>> def func(): ... raise IOError ... >>> try: ... func() ... except IOError as exc: ... raise RuntimeError('Failed to open database') from exc ... Traceback (most recent call last):File "<stdin>", line 2, in <module>File "<stdin>", line 2, in func OSErrorThe above exception was the direct cause of the following exception:Traceback (most recent call last):File "<stdin>", line 4, in <module> RuntimeError: Failed to open database上面的例子中,我們在捕獲IOError之后,又拋出了RuntimeError,通過使用異常鏈,我們很清晰的看出這兩個異常之間的關系。
默認情況下,如果異常是從except 或者 finally 中拋出的話,會自動帶上異常鏈信息。
如果你不想帶上異常鏈,那么可以 from None 。
try:open('database.sqlite') except IOError:raise RuntimeError from NoneTraceback (most recent call last):File "<stdin>", line 4, in <module> RuntimeError自定義異常
用戶可以繼承 Exception 來實現自定義的異常,我們看一些自定義異常的例子:
class Error(Exception):"""Base class for exceptions in this module."""passclass InputError(Error):"""Exception raised for errors in the input.Attributes:expression -- input expression in which the error occurredmessage -- explanation of the error"""def __init__(self, expression, message):self.expression = expressionself.message = messageclass TransitionError(Error):"""Raised when an operation attempts a state transition that's notallowed.Attributes:previous -- state at beginning of transitionnext -- attempted new statemessage -- explanation of why the specific transition is not allowed"""def __init__(self, previous, next, message):self.previous = previousself.next = nextself.message = messagefinally
try語句可以跟著一個finally語句來實現一些收尾操作。
>>> try: ... raise KeyboardInterrupt ... finally: ... print('Goodbye, world!') ... Goodbye, world! KeyboardInterrupt Traceback (most recent call last):File "<stdin>", line 2, in <module>finally 子句將作為 try 語句結束前的最后一項任務被執行, 無論try中是否產生異常,finally語句中的代碼都會被執行。
如果 finally 子句中包含一個 return 語句,則返回值將來自 finally 子句的某個 return 語句的返回值,而非來自 try 子句的 return 語句的返回值。
>>> def bool_return(): ... try: ... return True ... finally: ... return False ... >>> bool_return() False本文已收錄于 http://www.flydean.com/09-python-error-exception/
最通俗的解讀,最深刻的干貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!
歡迎關注我的公眾號:「程序那些事」,懂技術,更懂你!
總結
以上是生活随笔為你收集整理的Python基础之:Python中的异常和错误的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python基础之:Python中的IO
- 下一篇: Python基础之:Python中的内部