自訂例外


到目前你所看到的例外類別,都是Python預先定義的類別,它們都位於builtins模組之中。
>>> import builtins
>>> dir(builtins)
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'Buffer
Error', 'BytesWarning', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'Environme
ntError', 'Exception', 'False', 'FloatingPointError', 'FutureWarning', 'Generato
rExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexErr
or', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError',
 'None', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'P
endingDeprecationWarning', 'ReferenceError', 'RuntimeError', 'RuntimeWarning', '
StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'Ta
bError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'Unicod
eEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserW
arning', 'ValueError', 'Warning', 'WindowsError', 'ZeroDivisionError', 略...]
>>>


在Python 3中,所有的例外類別,其頂層父類別都是BaseException類別,然而直接繼承BaseException的有SystemExit、KeyboardInterrupt、GeneratorExit與Exception,前三者是有關於系統終止、鍵盤中斷以及產生器關閉的事件,在Python中,並非所有的例外都是錯誤,有些例外其實是事件通知的方式,像是KeyboardInterrupt、GeneratorExit與Exception。

如果你要自訂例外,並不是繼承BaseException,而是繼承BaseException的子類別Exception,非系統終止的事件都是繼承這個類別。例如:
>>> class SomeError(Exception):
...     pass
...
>>> try:
...     raise SomeError('some errors occured')
... except SomeError as e:
...     print(e.args)
...
('some errors occured',)
>>> try:
...     raise SomeError('some errors occured', 'more ....')
... except SomeError as e:
...     print(e.args)
...
('some errors occured', 'more ....')
>>>


如果你沒有重新定義__init__()方法,則會使用從Exception繼承下來的__init__()方法,你建立類別實例時所傳入的引數,則會收集為 Tuple 設定給Exception的args,又或者你可以定義自己的__init__()方法。例如:
>>> class OtherError(Exception):
...     def __init__(self, cause, message):
...         self.cause = cause
...         self.message = message
...     def __str__(self):
...         return self.cause + ': ' + self.message
...
>>> try:
...     raise OtherError('raise actively', 'user-defined exception example')
... except OtherError as e:
...     print(e)
...
raise actively: user-defined exception example
>>>


如果想要自訂定義類別,也可以在args中尋得建構實例時的訊息,則可以如下:
>>> class OtherError(Exception):
...     def __init__(self, cause, message):
...         super(Exception, self).__init__(cause, message)
...         self.cause = cause
...         self.message = message
...     def __str__(self):
...         return self.cause + ': ' + self.message
...
>>> try:
...     raise OtherError('raise actively', 'user-defined exception example')
... except OtherError as e:
...     print(e)
...     print(e.cause + "> " + e.message)
...     print(e.args[0] + ">> " + e.args[1])
...
raise actively: user-defined exception example
raise actively> user-defined exception example
raise actively>> user-defined exception example
>>>


再看 try、raise 中提過,except後 若不接上任何例外型態,則表示捕捉所有例外,這包括了所有的系統終止事件例外,如果你想要捕捉的是應用程式的錯誤所引發的例外,則可以在except上接上Exception。例如:
try:
    # some...
except Exception:
    # exception handler

你可以在 Built-in Exception 找到Python 3的例外類別相關說明,當中也列出了如下的例外繼承架構:
BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- ArithmeticError
      |    +-- FloatingPointError
      |    +-- OverflowError
      |    +-- ZeroDivisionError
      +-- AssertionError
      +-- AttributeError
      +-- BufferError
      +-- EnvironmentError
      |    +-- IOError
      |    +-- OSError
      |         +-- WindowsError (Windows)
      |         +-- VMSError (VMS)
      +-- EOFError
      +-- ImportError
      +-- LookupError
      |    +-- IndexError
      |    +-- KeyError
      +-- MemoryError
      +-- NameError
      |    +-- UnboundLocalError
      +-- ReferenceError
      +-- RuntimeError
      |    +-- NotImplementedError
      +-- SyntaxError
      |    +-- IndentationError
      |         +-- TabError
      +-- SystemError
      +-- TypeError
      +-- ValueError
      |    +-- UnicodeError
      |         +-- UnicodeDecodeError
      |         +-- UnicodeEncodeError
      |         +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
           +-- ImportWarning
           +-- UnicodeWarning
           +-- BytesWarning