跳轉到內容

Python 程式設計/異常

來自華夏公益教科書,開放的書籍,開放的世界


Python 2 使用異常處理所有錯誤。

異常 是一個訊號,表示發生了錯誤或其他異常情況。有很多內建異常,它們指示諸如讀取檔案結尾或除以零之類的條件。您還可以定義自己的異常。

Python 中的異常一覽

import random
try:
  ri = random.randint(0, 2)
  if ri == 0:
    infinity = 1/0
  elif ri == 1:
    raise ValueError("Message")
    #raise ValueError, "Message" # Deprecated
  elif ri == 2:
    raise ValueError # Without message
except ZeroDivisionError:
  pass
except ValueError as valerr:
# except ValueError, valerr: # Deprecated?
  print(valerr)
  raise # Raises the exception just caught
except: # Any other exception
  pass
finally: # Optional
  pass # Clean up

class CustomValueError(ValueError): pass # Custom exception
try:
  raise CustomValueError
  raise TypeError
except (ValueError, TypeError): # Value error catches custom, a derived class, as well
  pass                          # A tuple catches multiple exception classes

引發異常

[編輯 | 編輯原始碼]

每當您的程式嘗試進行錯誤或無意義的操作時,Python 都會對這種行為引發異常。

>>> 1 / 0
Traceback (most recent call last):
    File "<stdin>", line 1, in ?
ZeroDivisionError: integer division or modulo by zero

這個回溯 指示正在引發 ZeroDivisionError 異常。這是一個內建異常——請參閱下面的所有其他異常列表。

捕獲異常

[編輯 | 編輯原始碼]

為了處理錯誤,您可以在程式碼中設定異常處理塊。關鍵字 tryexcept 用於捕獲異常。當 try 塊中發生錯誤時,Python 會查詢匹配的 except 塊來處理它。如果有,執行將跳轉到那裡。

如果您執行此程式碼

try:
    print(1/0)
except ZeroDivisionError:
    print("You can't divide by zero!")

那麼 Python 將列印此內容

您不能除以零!

如果您沒有在 except 行上指定異常型別,它會愉快地捕獲所有異常。這在生產程式碼中通常是一個壞主意,因為它意味著您的程式會愉快地忽略意外 錯誤以及 except 塊實際準備處理的錯誤。

異常可以沿著呼叫棧傳播

def f(x):
    return g(x) + 1

def g(x):
    if x < 0: raise ValueError, "I can't cope with a negative number here."
    else: return 5

try:
    print(f(-6))
except ValueError:
    print("That value was invalid.")

在此程式碼中,print 語句呼叫函式 f。該函式呼叫函式 g,後者將引發型別為 ValueError 的異常。fg 都沒有 try/except 塊來處理 ValueError。因此,引發的異常會傳播到主程式碼,在那裡有一個 異常處理塊在等待它。此程式碼列印

該值無效。

有時找出確切的錯誤或自己列印 python 錯誤文字很有用。例如

try:
    the_file = open("the_parrot")
except IOError, (ErrorNumber, ErrorMessage):
    if ErrorNumber == 2: # file not found
        print("Sorry, 'the_parrot' has apparently joined the choir invisible.")
    else:
        print("Congratulation! you have managed to trip a #%d error" % ErrorNumber)
        print(ErrorMessage)

這將列印

抱歉,'the_parrot' 顯然加入了無形的合唱團。

自定義異常

[編輯 | 編輯原始碼]

類似於上面看到的程式碼可用於建立自定義異常並將資訊與它們一起傳遞。這在嘗試除錯複雜專案時非常有用。以下是該程式碼的外觀;首先建立自定義異常類

class CustomException(Exception):
    def __init__(self, value):
        self.parameter = value
    def __str__(self):
        return repr(self.parameter)

然後使用該異常

try:
    raise CustomException("My Useful Error Message")
except CustomException, (instance):
    print("Caught: " + instance.parameter)

反覆嘗試

[編輯 | 編輯原始碼]

使用 finally 恢復和繼續

[編輯 | 編輯原始碼]

異常可能導致一種情況,即在引發異常後,可能不會重新訪問發生異常的程式碼塊。在某些情況下,這可能會使程式使用的外部資源處於未知狀態。

finally 子句允許程式設計師在發生異常的情況下關閉此類資源。在 python 的 2.4 和 2.5 版本之間,finally 子句的語法發生了變化。

  • Python 2.4
try:
    result = None
    try:
        result = x/y
    except ZeroDivisionError:
        print("division by zero!")
    print("result is ", result)
finally:
    print("executing finally clause")
  • Python 2.5
try:
    result = x / y
except ZeroDivisionError:
    print("division by zero!")
else:
    print("result is", result)
finally:
    print("executing finally clause")

內建異常類

[編輯 | 編輯原始碼]

所有內建 Python 異常

異常的奇特用法

[編輯 | 編輯原始碼]

異常不僅僅用於錯誤處理。如果您有一段複雜的程式碼來選擇要採取的幾種行動中的哪一種,那麼使用異常可以幫助您在做出決定後立即退出程式碼。基於 Python 的郵件列表軟體 Mailman 在決定如何處理郵件時就是這樣做的。使用這種異常可能看起來像是某種 GOTO——實際上它是,但它是一種稱為轉義延續 的有限的 GOTO。延續是一種強大的函數語言程式設計工具,學習它們很有用。

作為異常使程式設計更容易的簡單示例,假設您想向列表中新增專案,但不想使用“if”語句來初始化列表,我們可以用此替換

if hasattr(self, 'items'):
    self.items.extend(new_items)
else:
    self.items = list(new_items)

使用異常,我們可以強調正常的程式流程——即我們通常只是擴充套件列表——而不是強調異常情況

try:
    self.items.extend(new_items)
except AttributeError:
    self.items = list(new_items)
[編輯 | 編輯原始碼]
華夏公益教科書