例外の階層構造
Pythonでは、すべての例外は
BaseException
クラスから派生しています。つまり、Pythonの例外はすべてBaseException
またはそのサブクラスのインスタンスです。BaseException
クラスは例外階層の最上位のクラスであり、__str__
や__repr__
など、すべての例外が使用できる共通のメソッドを提供します。しかし、BaseException
を直接コードで使用するべきではありません。なぜなら、それは範囲が広すぎて、あらゆる種類の例外を捕捉してしまうからです。代わりに、BaseException
のサブクラスであるより具体的な例外クラスを使用するべきです。Pythonは多くの組み込み例外クラスを提供しており、自分自身でカスタムの例外クラスを作成することもできます:BaseException
├── BaseExceptionGroup
├── GeneratorExit
├── KeyboardInterrupt
├── SystemExit
└── Exception
├── ArithmeticError
│ ├── FloatingPointError
│ ├── OverflowError
│ └── ZeroDivisionError
├── AssertionError
├── AttributeError
├── BufferError
├── EOFError
├── ExceptionGroup [BaseExceptionGroup]
├── ImportError
│ └── ModuleNotFoundError
├── LookupError
│ ├── IndexError
│ └── KeyError
├── MemoryError
├── NameError
│ └── UnboundLocalError
├── OSError
│ ├── BlockingIOError
│ ├── ChildProcessError
│ ├── ConnectionError
│ │ ├── BrokenPipeError
│ │ ├── ConnectionAbortedError
│ │ ├── ConnectionRefusedError
│ │ └── ConnectionResetError
│ ├── FileExistsError
│ ├── FileNotFoundError
│ ├── InterruptedError
│ ├── IsADirectoryError
│ ├── NotADirectoryError
│ ├── PermissionError
│ ├── ProcessLookupError
│ └── TimeoutError
├── ReferenceError
├── RuntimeError
│ ├── NotImplementedError
│ └── RecursionError
├── StopAsyncIteration
├── StopIteration
├── SyntaxError
│ └── IndentationError
│ └── TabError
├── SystemError
├── TypeError
├── ValueError
│ └── UnicodeError
│ ├── UnicodeDecodeError
│ ├── UnicodeEncodeError
│ └── UnicodeTranslateError
└── Warning
├── BytesWarning
├── DeprecationWarning
├── EncodingWarning
├── FutureWarning
├── ImportWarning
├── PendingDeprecationWarning
├── ResourceWarning
├── RuntimeWarning
├── SyntaxWarning
├── UnicodeWarning
└── UserWarning
つまり、
FileNotFoundError
はOSError
のサブクラスであり、OSError
はException
クラスのサブクラスで、そのException
クラス自体がBaseException
から継承されています。 例外の階層構造を尊重する
複数の
except
文を使用する際には、Pythonの例外階層構造を尊重することが重要です。つまり、Exception
のような基底の例外クラスを捕捉する場合、より具体的な例外をその前に捕捉する必要があります。もし基底クラスの後により具体的なクラスのexcept
文を書いても、そのブロックは実行されません:try:
# 例外を発生させる可能性のあるコード
except ValueError:
# ValueErrorを処理する
except Exception:
# その他の例外を処理する
この例では、
ValueError
例外が最初に捕捉されます。コードが他のException
から派生した例外を発生させた場合、2つ目のexcept
ブロックのコードが実行されます。しかし、Exception
を直接捕捉することはおすすめできません。これは範囲が広すぎて、あらゆる種類の例外を捕捉してしまうからです。可能な限り、より具体的な例外を捕捉する方がよいでしょう:try:
...
except TypeError:
...
except ValueError:
...
except Exception:
...
try
ブロック内のコードがTypeError
やValueError
を発生させた場合、それぞれ対応するexcept
ブロックが実行されます。コードが他のException
から派生した例外を発生させた場合、3つ目のexcept
ブロックのコードが実行されます。もし基底の例外を最初の
except
ブロックに置くと、残りのブロックは決して実行されません:try:
# 例外を発生させる可能性のあるコード
except Exception as e: # これはすべてのエラーを捕捉します
print(f'An error occurred: {e}')
except ValueError: # これは実行されません
print('A ValueError occurred')
except TypeError: # これは実行されません
print('A TypeError occurred')
この例では、
try
ブロックは任意の種類の例外を発生させる可能性があります。しかし、最初のexcept
文が基底のException
クラスを捕捉しているため、発生したすべての例外を捕捉します。エラーメッセージが表示され、残りのexcept
文は実行されません。 チャレンジ:ファイルを解析する
あなたは大量のデータを扱うスタートアップでソフトウェアエンジニアとして働いています。最近、チームはデータの保存と処理にJSONファイルを使用することを決定しました。このデータはあなたのスタートアップの運営にとって非常に重要であり、これらのJSONファイルを読み込み解析するPythonプログラムを作成するのがあなたの仕事です。
しかし、大量のデータと複数の人が関わっているため、いくつかのエラーが頻繁に発生します:
- データファイルが存在しない場合があります。
- データファイルが空の場合があります。
- データファイルに有効なJSONでないデータが含まれている場合があります。
あなたのPythonプログラムは、これらの例外をクラッシュせずに処理し、データチームが迅速に問題を特定し修正できるよう、意味のあるエラーメッセージを提供する必要があります。
あなたのプログラムは、ファイル名を表す文字列を入力として受け取り、次のケースに対応する必要があります:
- ファイルが存在しない場合、
FileNotFoundError
を発生させ、適切なエラーメッセージを表示します。
- ファイルが空の場合、
ValueError
を発生させ、適切なエラーメッセージを表示します。
- ファイルの内容が有効なJSONでない場合、
json.JSONDecodeError
(ValueError
のサブクラス)を発生させ、適切なエラーメッセージを表示します。この例外を発生させる際には、doc
とpos
の属性をパラメータとして提供する必要があります。
💡
except json.JSONDecodeError as e:
これらの例外はそれぞれ独立して処理されるべきであり、あなたのプログラムは各ケースに対して具体的なエラーメッセージを提供する必要があります。
入力 | 出力 |
nonexistent_file.json | FileNotFoundError: File 'nonexistent_file.json' does not exist. |
empty_file.json | ValueError: File 'empty_file.json' is empty. |
invalid_json.json | JSONDecodeError: Content of file 'invalid_json.json' is not valid JSON.: line 1 column 1 (char 0) |
success.json | File 'success.json' has been successfully parsed as valid JSON. |
Constraints
Time limit: 2 seconds
Memory limit: 512 MB
Output limit: 1 MB