Python - 異常處理



Python中的異常處理

Python 中的異常處理是指管理程式執行過程中可能發生的執行時錯誤。在 Python 中,當程式執行過程中出現錯誤或意外情況時,例如除以零、嘗試訪問不存在的檔案或嘗試對不相容的資料型別執行操作,就會引發異常。

Python 提供了兩個非常重要的功能來處理 Python 程式中任何意外錯誤並在其中新增除錯功能:

  • 異常處理 - 本教程將對此進行介紹。以下是 Python 中提供的標準異常列表:標準異常

  • 斷言 - 這將在Python 中的斷言 教程中介紹。

Python 中的斷言

斷言是一種健全性檢查,您可以在完成程式測試後將其開啟或關閉。

最簡單的理解斷言的方法是將其比作raise-if語句(更準確地說,是raise-if-not語句)。測試一個表示式,如果結果為假,則引發異常。

斷言由assert語句執行,assert是Python中最新引入的關鍵字,在1.5版本中引入。

程式設計師經常在函式開頭放置斷言以檢查有效輸入,並在函式呼叫後檢查有效輸出。

assert 語句

當遇到assert語句時,Python會評估隨附的表示式,該表示式應該為真。如果表示式為假,Python會引發AssertionError異常。

assert的語法為:

assert Expression[, Arguments]

如果斷言失敗,Python 將使用 ArgumentExpression 作為 AssertionError 的引數。可以使用 try-except 語句捕獲和處理 AssertionError 異常,但如果未處理,它們將終止程式併產生回溯。

示例

這是一個將溫度從開爾文度轉換為華氏度的函式。由於零開爾文度是最低溫度,因此如果看到負溫度,則函式將退出:

def KelvinToFahrenheit(Temperature):
   assert (Temperature >= 0),"Colder than absolute zero!"
   return ((Temperature-273)*1.8)+32
print (KelvinToFahrenheit(273))
print (int(KelvinToFahrenheit(505.78)))
print (KelvinToFahrenheit(-5))

執行上述程式碼時,將產生以下結果:

32.0
451
Traceback (most recent call last):
File "test.py", line 9, in <module>
print (KelvinToFahrenheit(-5))
File "test.py", line 4, in KelvinToFahrenheit
assert (Temperature >= 0),"Colder than absolute zero!"
AssertionError: Colder than absolute zero!

什麼是異常?

異常是在程式執行期間發生並中斷程式指令正常流程的事件。一般來說,當 Python 指令碼遇到無法處理的情況時,它會引發異常。異常是一個表示錯誤的 Python 物件。

當 Python 指令碼引發異常時,它必須立即處理該異常,否則它將終止並退出。

Python 中的異常處理

如果你的程式碼中有一些可能引發異常的可疑部分,你可以透過將這些可疑程式碼放在一個try: 塊中來保護你的程式。在try: 塊之後,包含一個except: 語句,後面跟著一段程式碼,這段程式碼儘可能優雅地處理問題。

  • try: 塊包含可能引發異常的語句。

  • 如果發生異常,程式跳轉到except: 塊。

  • 如果try: 塊中沒有異常,則跳過except: 塊。

語法

這是try...except...else 塊的簡單語法:

try:
   You do your operations here
   ......................
except ExceptionI:
   If there is ExceptionI, then execute this block.
except ExceptionII:
   If there is ExceptionII, then execute this block.
   ......................
else:
   If there is no exception then execute this block.

關於上述語法,以下是一些重要點:

  • 單個try語句可以有多個except語句。當try塊包含可能丟擲不同型別異常的語句時,這很有用。

  • 你也可以提供一個泛型except子句,它處理任何異常。

  • 在except子句之後,你可以包含一個else子句。如果try: 塊中的程式碼沒有引發異常,則執行else塊中的程式碼。

  • else塊是放置不需要try: 塊保護的程式碼的好地方。

示例

此示例開啟一個檔案,在檔案中寫入內容,並優雅地退出,因為根本沒有問題。

try:
   fh = open("testfile", "w")
   fh.write("This is my test file for exception handling!!")
except IOError:
   print ("Error: can\'t find file or read data")
else:
   print ("Written content in the file successfully")
   fh.close()

它將產生以下輸出

Written content in the file successfully

但是,將open()函式中的mode引數更改為“w”。如果testfile不存在,程式會在except塊中遇到IOError,並列印以下錯誤訊息:

Error: can't find file or read data

示例

此示例嘗試開啟一個你沒有寫入許可權的檔案,因此它會引發異常:

try:
   fh = open("testfile", "r")
   fh.write("This is my test file for exception handling!!")
except IOError:
   print ("Error: can\'t find file or read data")
else:
   print ("Written content in the file successfully")

這將產生以下結果:

Error: can't find file or read data

except 子句,無異常

你也可以使用沒有定義異常的except語句,如下所示:

try:
   You do your operations here;
   ......................
except:
   If there is any exception, then execute this block.
   ......................
else:
   If there is no exception then execute this block. 

這種try-except語句捕獲所有發生的異常。但是,使用這種try-except語句不被認為是良好的程式設計實踐,因為它捕獲所有異常,但不會讓程式設計師識別可能發生的問題的根本原因。

except 子句,多個異常

你也可以使用相同的except語句來處理多個異常,如下所示:

try:
   You do your operations here;
   ......................
except(Exception1[, Exception2[,...ExceptionN]]]):
   If there is any exception from the given exception list, 
   then execute this block.
   ......................
else:
   If there is no exception then execute this block. 

try-finally 子句

你可以將finally: 塊與try: 塊一起使用。finally塊是放置必須執行的任何程式碼的地方,無論try塊是否引發異常。try-finally語句的語法如下:

try:
   You do your operations here;
   ......................
   Due to any exception, this may be skipped.
finally:
   This would always be executed.
   ......................

你不能與finally子句一起使用else子句。

示例

try:
   fh = open("testfile", "w")
   fh.write("This is my test file for exception handling!!")
finally:
   print ("Error: can\'t find file or read data")

如果你沒有許可權以寫入模式開啟檔案,則會產生以下結果:

Error: can't find file or read data

同一個例子可以更簡潔地寫成如下:

try:
   fh = open("testfile", "w")
   try:
      fh.write("This is my test file for exception handling!!")
   finally:
      print ("Going to close the file")
      fh.close()
except IOError:
   print ("Error: can\'t find file or read data")

try塊中丟擲異常時,執行立即傳遞到finally塊。在執行finally塊中的所有語句之後,異常將再次被丟擲,如果在try-except語句的下一較高層中存在,則在except語句中進行處理。

異常的引數

異常可以有一個引數,它是一個提供有關問題更多資訊的 value。引數的內容因異常而異。你可以透過在except子句中提供一個變數來捕獲異常的引數,如下所示:

try:
   You do your operations here;
   ......................
except ExceptionType, Argument:
   You can print value of Argument here...

如果你編寫程式碼來處理單個異常,你可以在except語句中在異常名稱後新增一個變數。如果你正在捕獲多個異常,你可以在異常元組後新增一個變數。

此變數接收異常的值,該值主要包含異常的原因。變數可以接收單個值或元組形式的多個值。此元組通常包含錯誤字串、錯誤號和錯誤位置。

示例

以下是單個異常的示例:

# Define a function here.
def temp_convert(var):
   try:
      return int(var)
   except ValueError as Argument:
      print ("The argument does not contain numbers\n", Argument)

# Call above function here.
temp_convert("xyz")

這將產生以下結果:

The argument does not contain numbers
invalid literal for int() with base 10: 'xyz'

引發異常

你可以透過使用raise語句以幾種方式引發異常。raise語句的一般語法如下所示。

語法

raise [Exception [, args [, traceback]]]

這裡,Exception是異常的型別(例如,NameError),argument是異常引數的值。引數是可選的;如果未提供,則異常引數為None。

最終引數,回溯,也是可選的(在實踐中很少使用),如果存在,則是用於異常的回溯物件。

示例

異常可以是字串、類或物件。Python核心引發的多數異常都是類,其引數是該類的例項。定義新異常非常容易,可以按如下方式完成:

def functionName( level ):
   if level < 1:
      raise "Invalid level!", level
      # The code below to this would not be executed
      # if we raise the exception

注意:為了捕獲異常,“except”子句必須引用丟擲的相同異常,無論是類物件還是簡單的字串。例如,要捕獲上述異常,我們必須按如下方式編寫except子句:

try:
   Business Logic here...
except "Invalid level!":
   Exception handling here...
else:
   Rest of the code here...

使用者自定義異常

Python還允許你透過從標準內建異常派生類來建立你自己的異常。

這是一個與RuntimeError相關的示例。這裡,建立了一個從RuntimeError派生的類。當需要在捕獲異常時顯示更具體的 資訊時,這很有用。

在try塊中,引發使用者定義的異常並在except塊中捕獲。變數e用於建立類Networkerror的例項。

class Networkerror(RuntimeError):
   def __init__(self, arg):
      self.args = arg

因此,一旦你定義了上述類,你就可以按如下方式引發異常:

try:
   raise Networkerror("Bad hostname")
except Networkerror,e:
   print (e.args)

標準異常

以下是Python中提供的標準異常列表:

序號 異常名稱和描述
1

異常

所有異常的基類

2

StopIteration

當迭代器的next()方法不指向任何物件時引發。

3

SystemExit

由sys.exit()函式引發。

4

StandardError

除StopIteration和SystemExit之外的所有內建異常的基類。

5

ArithmeticError

所有針對數字計算發生的錯誤的基類。

6

OverflowError

當計算超過數值型別的最大限制時引發。

7

FloatingPointError

當浮點計算失敗時引發。

8

ZeroDivisionError

當對所有數字型別進行除法或模零運算時引發。

9

AssertionError

在Assert語句失敗的情況下引發。

10

AttributeError

在屬性引用或賦值失敗的情況下引發。

11

EOFError

當raw_input()或input()函式沒有輸入並且到達檔案結尾時引發。

12

ImportError

當import語句失敗時引發。

13

KeyboardInterrupt

當用戶中斷程式執行時引發,通常是透過按Ctrl+c。

14

LookupError

所有查詢錯誤的基類。

15

IndexError

當在序列中找不到索引時引發。

16

KeyError

當在字典中找不到指定的鍵時引發。

17

NameError

當在本地或全域性名稱空間中找不到識別符號時引發。

18

UnboundLocalError

當嘗試訪問函式或方法中的區域性變數但未為其賦值時引發。

19

EnvironmentError

發生在Python環境之外的所有異常的基類。

20

IOError

當輸入/輸出操作失敗時引發,例如print語句或open()函式在嘗試開啟不存在的檔案時。

21

IOError

針對與作業系統相關的錯誤引發。

22

SyntaxError

當Python語法錯誤時引發。

23

IndentationError

當縮排未正確指定時引發。

24

SystemError

當直譯器發現內部問題時引發,但是當遇到此錯誤時,Python直譯器不會退出。

25

SystemExit

當使用sys.exit()函式退出Python直譯器時引發。如果程式碼中未處理,則導致直譯器退出。

26

TypeError

當嘗試對指定資料型別無效的操作或函式時引發。

27

ValueError

當資料型別的內建函式具有有效的引數型別,但引數具有指定的無效值時引發。

28

RuntimeError

當生成的錯誤不屬於任何類別時引發。

29

NotImplementedError

當需要在繼承類中實現的抽象方法實際上未實現時引發。

廣告