1050: 例外階層の最近共通祖先¶
問題¶
except C: という節は、送出された例外が C のインスタンス、すなわち C またはその派生クラスのインスタンスであるときにマッチします。
したがって、複数種類の例外を一つの except 節で捕捉したいときは、それらの共通の基底クラスを指定すれば足ります。
組み込み例外は BaseException を根とする木構造をなすので、「与えられた例外クラスをすべて捕捉でき、その中で最も特殊なクラス」は木構造でいう最近共通祖先(lowest common ancestor)です。
関数 common_handler(*exc_types) を実装してください。
1個以上の例外クラスを受け取り、そのすべてを1つの except 節で捕捉できるクラスのうち、継承の木で最も深いものを返します。
各クラスの継承関係は __mro__ 属性から読み取ります。
制約¶
- 引数はそれぞれ
BaseExceptionまたはその派生クラスです。 - 例外クラスでない引数(例外クラスのインスタンスや、
BaseExceptionを継承しないクラスを含む)が1つでもあればTypeErrorを送出します。 - 引数が0個の場合も
TypeErrorを送出します。 Exception系とSystemExitやKeyboardInterruptなどのBaseException直下の系統が混在する場合も正しく扱います。- 組み込み例外と同様の単一継承の木構造を仮定してかまいません。
例¶
>>> common_handler(FileNotFoundError, PermissionError)
<class 'OSError'>
>>> common_handler(IndexError, KeyError)
<class 'LookupError'>
>>> common_handler(ZeroDivisionError, OverflowError)
<class 'ArithmeticError'>
>>> common_handler(KeyError, UnicodeDecodeError)
<class 'Exception'>
>>> common_handler(ValueError, KeyboardInterrupt)
<class 'BaseException'>
>>> common_handler(FileNotFoundError)
<class 'FileNotFoundError'>
>>> common_handler(int, str)
Traceback (most recent call last):
...
TypeError: <class 'int'> is not an exception class
>>> common_handler()
Traceback (most recent call last):
...
TypeError: at least one exception class is required
発展¶
多重継承された例外クラスでは最近共通祖先が一意に決まるとは限りません。
OSError と ValueError の両方を継承したユーザ定義例外を2つ作り、common_handler が何を返すかを確かめてください。
その返り値が引数の並び順に依存するかどうかも調べ、__mro__ の線形化がこの問題にどう関わるかを説明してください。
参考¶
- 『Python Distilled』第10章「組み込み例外」
- 『Python Distilled』第10章「基底例外クラス」
- 『Python Distilled』第10章「組み込み例外クラス」
- 最小共通祖先 - Wikipedia