問題の歴史:
Pythonでは例外システムが最初から存在し、クラスに基づいて構築されています。すべての例外の階層は基底クラスBaseExceptionから継承されます。実際には、独自の例外はExceptionから作成されます。ユーザー定義の例外の開発は、大規模プロジェクトにとって重要です — アプリケーションの特定のエラーをより正確に処理し、通知します。
問題:
すべての開発者がBaseExceptionとExceptionの違いを理解しているわけではなく、自分のクラスを作成するのが面倒だと感じ、一般的なcatchブロックを使用することが、望ましくない例外(例えば、SystemExit、KeyboardInterrupt)を吸収し、アクセスしにくいバグを引き起こします。しばしば、例外クラスは適切に実装されておらず、意味のある名前を指定せずに必要なクラスから継承されていません。
解決策:
独自の例外をExceptionの子クラスとして作成します。意味のある名前を使用して、すべての基本的なエラーを捕まえないようにします。BaseExceptionからではなく、Exceptionまたはその派生クラスからのみ継承し、具体的なクラスを指定せずにexcept:で全てを捕まえないようにします。
コード例:
class MyAppError(Exception): """アプリケーションの例外の基底クラス""" pass class ConfigFileNotFound(MyAppError): pass try: raise ConfigFileNotFound('設定ファイルが見つかりません!') except ConfigFileNotFound as e: print(f'エラー: {e}')
重要な特徴:
タイプを指定せずに"except:"ですべての例外を捕まえることの危険性は何ですか?
このブロックは、システム例外であるKeyboardInterruptやSystemExitまでも捕まえてしまうため、Ctrl+Cでプログラムを正常に終了することが不可能になり、クリティカルな状況で「ハング」することになります。基本的なシステムイベントをスキップするために「except Exception:」を書くべきです。
独自の例外をBaseExceptionから継承することはできますか?
技術的には可能ですが、絶対にお勧めしません — このような例外は検出が難しく、標準のExceptionハンドラーを回避するため、アプリケーションで未捕捉のエラーを引き起こすことがよくあります。
ユーザー定義の例外の代わりにValueErrorやTypeErrorを使用することは正しいでしょうか?
小さなスクリプトでは許容されますが、大規模プロジェクトでは、独自の意味のある例外を作成するのが望ましいです。これにより、アプリケーションの上位レベルでのエラーの診断と処理が迅速になります。
# 誤り: raise ValueError('アプリケーションに特有の何か') # 良い: class MyAppValueError(MyAppError): pass raise MyAppValueError('アプリケーションのコンテキストを有するエラーの説明')
大規模なプロジェクトで、グローバルなtry/except:ブロックがあり、システム例外を捕まえていました。いくつかのエラー(例えば、SystemExit)がログに表示されず、アプリケーションが予期しない状態に陥り、管理者が症状を長い間探しました。
利点:
欠点:
独自のエラークラスが定義され、常に「except Exception: ...」が使用され、ユーザー定義の例外のための個別のハンドラーがありました。
利点:
欠点: