Python異常處理

Python提供了兩個非常重要的功能來處理Python程序中的異常和錯誤,並在其中添加調試的函數功能 -

  • 異常處理 - 在本教程中介紹。這是一個列表標準Python中提供的異常 - 標準異常。
  • 斷言 - 在Python 3教程中的斷言中介紹。

標準異常

以下是Python中可用的標準異常列表 -

編號

異常名稱

描述

1

Exception

所有異常的基類

2

StopIteration

當迭代器的next()方法沒有指向任何對象時引發。

3

SystemExit

sys.exit()函數引發。

4

StandardError

StopIterationSystemExit之外的所有內置異常的基類。

5

ArithmeticError

數據計算出現的所有錯誤的基類。

6

OverflowError

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

7

FloatingPointError

當浮點計算失敗時觸發。

8

ZeroDivisonError

對於所有的數字類型,當對零進行除數或模數時產生。

9

AssertionError

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

10

AttributeError

在屬性引用或分配失敗的情況下引發。

11

EOFError

當沒有來自raw_input()input()函數的輸入並且達到文件結尾時引發。

12

ImportError

導入語句失敗時引發。

13

KeyboardInterrupt

當用戶中斷程序執行時,通常按Ctrl + c

14

LookupError

所有查找錯誤的基類。

15

IndexError

當序列中沒有找到索引時引發。

16

KeyError

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

17

NameError

當在本地或全局命名空間中找不到標識符時引發。

18

UnboundLocalError

當嘗試訪問函數或方法中的局部變量但未分配值時引發。

19

EnvironmentError

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

20

IOError

在嘗試打開不存在的文件時,輸入/輸出操作失敗時觸發,例如print語句或open()函數。

21

OSError

引起操作系統相關的錯誤。

22

SyntaxError

當Python語法有錯誤時引發。

23

IndentationError

當縮進未正確指定時觸發。

24

SystemError

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

25

SystemExit

當Python解釋器通過使用sys.exit()函數退出時引發。 如果沒有在代碼中處理,導致解釋器退出。

26

TypeError

在嘗試對指定數據類型無效的操作或函數時引發。

27

ValueError

當數據類型的內置函數具有有效參數類型時引發,但參數具有指定的無效值。

28

RuntimeError

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

29

NotImplementedError

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

Python中的斷言

斷言是一個健全檢查,可以在完成對程序的測試後打開或關閉。

  • 試想斷言的最簡單的方法就是將它與一個raise-if語句(或者更準確的說是一個加註if語句)相對應。測試表達式,如果結果爲false,則會引發異常。

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

  • 程序員經常在函數開始時放置斷言來檢查有效的輸入,並在函數調用後檢查有效的輸出。

assert語句

當它遇到一個assert語句時,Python會評估求值它的的表達式,是否爲所希望的那樣。 如果表達式爲false,Python會引發AssertionError異常。

assert的語法是 -

assert Expression[, Arguments]

如果斷言失敗,Python將使用ArgumentExpression作爲AssertionError的參數。 使用try-except語句可以像任何其他異常一樣捕獲和處理AssertionError異常。 如果沒有處理,它們將終止程序併產生回溯。
**
示例**

這裏將實現一個功能:將給定的溫度從開爾文轉換爲華氏度。如果是負溫度,該功能將退出 -

#!/usr/bin/python3
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腳本引發異常時,它必須立即處理異常,否則終止並退出。

處理異常

如果有一些可能引發異常的可疑代碼,可以通過將可疑代碼放在try:塊中來保護您的程序。 在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:block中的代碼不引發異常,則else塊中的代碼將執行。
  • else-block是一個不需要try:block保護的代碼的地方。

示例

此示例打開一個文件,將內容寫入文件,並且優雅地出現,因爲完全沒有問題 -

#!/usr/bin/python3

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

示例

此示例嘗試打開一個沒有寫入權限的文件,因此它引發了一個異常 -

#!/usr/bin/python3

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.
   ......................

注意 - 可以提供except子句或finally子句,但不能同時提供。不能使用else子句以及finally子句。

示例

#!/usr/bin/python3

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")
   fh.close()

如果沒有以寫入形式打開文件的權限,則會產生以下結果 -

Error: can't find file or read data

同樣的例子可以寫得更乾淨如下 -

#!/usr/bin/python3

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語句中處理異常。

異常參數

一個異常可以有一個參數,參數它是一個值,它提供有關該問題的其他信息。 參數的內容因異常而異。 可以通過在except子句中提供變量來捕獲異常的參數,如下所示:

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

如果編寫代碼來處理單個異常,則可以在except語句中使用一個變量後跟異常的名稱。 如果要捕獲多個異常,可以使用一個變量後跟隨異常的元組。

此變量接收大部分包含異常原因的異常值。 變量可以以元組的形式接收單個值或多個值。 該元組通常包含錯誤字符串,錯誤編號和錯誤位置。

示例

以下是一個例外 -

#!/usr/bin/python3

# 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),args是異常參數的值。 參數是可選的; 如果沒有提供,則異常參數爲None

最後一個參數traceback也是可選的(在實踐中很少使用),如果存在,則是用於異常的追溯對象。

示例

異常可以是字符串,類或對象。 Python核心引發的大多數異常都是類,一個參數是類的一個實例。 定義新的例外是非常容易的,可以做到如下 -

def functionName( level ):
   if level <1:
      raise Exception(level)
      # The code below to this would not be executed
      # if we raise the exception
   return level

注意 - 爲了捕獲異常,「except」子句必須引用與類對象或簡單字符串相同的異常。例如,爲了捕獲上述異常,必須寫出except子句如下:

try:
   Business Logic here...
except Exception as e:
   Exception handling here using e.args...
else:
   Rest of the code here...

以下示例說明了使用引發異常 -

#!/usr/bin/python3
def functionName( level ):
   if level <1:
      raise Exception(level)
      # The code below to this would not be executed
      # if we raise the exception
   return level

try:
   l = functionName(-10)
   print ("level = ",l)
except Exception as e:
   print ("error in level argument",e.args[0])

這將產生以下結果 -

error in level argument -10

用戶定義的異常

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