Python 3 エンジニア認定基礎試験 想定問題集
エラーと例外の要点整理と想定問題
公式の出題範囲の「8章 エラーと例外」にあたる分野です。まず要点整理で全体をつかみ、下の演習で 29 問を 1 問ずつ解けます。答えると A〜D すべての解説が出ます。
この分野の小項目
- 8.1 構文エラー(3 問) 構文エラー(SyntaxError・パースエラー)は、プログラムを解析する段階で見つかる誤り。パーサはエラーを検出した行を表示し、問題の箇所を矢印などで示す。ファイル名と行番号も表示される。
- 8.2 例外とトレースバック(4 問) 構文が正しくても実行中に検出されるエラーが例外。ZeroDivisionError・NameError・TypeError など型によって種類が分かれ、エラーメッセージの最後の行に例外の型と詳細が表示される。その前にはスタックトレースバックが表示される。組み込み例外は標準ライブラリの「組み込み例外」に一覧がある。
- 8.3 try 文と except 節(4 問) try 節を実行して例外が起きなければ except 節を飛ばす。例外が起きると残りを飛ばし、型が一致する except 節を実行する。一致しなければ外側の try に渡し、処理されなければ未処理例外で止まる。except 節は複数書け、実行されるハンドラは最大 1 つ。1 つの except 節に複数の例外を指定できる(第4版の Python 3.9 では丸括弧で囲んだタプルで書く。現行の Web 版は括弧なしの例を載せている)。基底クラスの except は派生クラスの例外にも一致するため、並べる順番に注意する。
- 8.3 例外の引数・else 節・Exception と BaseException(4 問) except 節で as を使うと例外インスタンスを受け取れ、args に引数が入る。try ... except には全ての except 節の後に else 節を書け、try 節で例外が起きなかったときに実行される。Exception はシステム終了以外の例外の基底クラスで、BaseException は全例外の基底クラス(KeyboardInterrupt や SystemExit は Exception の派生ではない)。
- 8.4・8.5 例外の送出と連鎖(raise・from)(5 問) raise 文で指定した例外を発生させる。引数は例外インスタンスか例外クラス(引数なしで暗黙にインスタンス化)。except 節の中で引数なしの raise を書くと、その例外を再送出する。except 節で別の例外が起きると元の例外が添えられる(連鎖)。raise ... from ... で直接の原因を明示でき、from None で連鎖を無効にできる。
- 8.6 ユーザー定義例外(3 問) 新しい例外クラスを作ると独自の例外を定義できる。例外は通常 Exception クラスを直接または間接に継承し、名前は標準の例外にならって Error で終わるものが多い。
- 8.7 クリーンアップ動作(finally 節)(3 問) finally 節は try 文が例外の有無にかかわらず終わる前に必ず実行される。処理されなかった例外は finally 節の実行後に再送出される。finally 節で break・continue・return を実行すると例外は再送出されない。try 節の return より前に finally 節が実行され、finally 節に return があればその値が戻り値になる。外部資源の解放に使う。
- 8.8 定義済みクリーンアップ処理(with 文)(3 問) ファイルなど一部のオブジェクトには、不要になったときの標準的なクリーンアップ処理が定義されている。with 文を使うと、処理中に問題が起きても使い終わったファイルが必ず正しく閉じられる。
要点整理
構文エラー
構文エラー:見つかるのは実行の前、^ は直す場所とは限らない
SyntaxError(構文エラー・パースエラー)は、文法に合わない書き方で起きるエラーです。プログラムを解析(パース)する段階で見つかります。
パーサは誤りを見つけた行を表示し、検出した位置に ^ を付けます。ただし ^ の場所が直す場所とは限りません。while True print('Hello world') では ^ は print を指しますが、原因は while True の後のコロンの抜けです。
ファイルから読み込んだコードなら、ファイル名と行番号も表示されます。ファイルは実行の前に全体が解析されるので、3 行目に構文エラーがあると 1 行目の print も実行されません。
例外とトレースバック
例外とトレースバック:最後の行に型と詳細
文法が正しくても、実行しようとしたときにエラーが起きることがあります。これが例外で、必ずしも致命的ではなく、プログラムの中で処理できます。
例外は型で種類が分かれます。0 で割ると ZeroDivisionError、定義していない名前を使うと NameError、文字列と数値を + でつなぐと TypeError です。int('3.5') のように型は合っていても値が使えないときは ValueError になります。
処理されない例外はエラーメッセージを出します。最後の行には、何が起きたかが例外の型と詳細の形で表示されます。その上には、例外が起きるまでの呼び出しの記録であるトレースバックが表示されます。
標準の例外の名前は組み込みの識別子で、予約語ではありません。組み込みの例外の一覧と意味は、標準ライブラリの「組み込み例外」にまとまっています。
| コード | 起きる例外 | 理由 |
|---|---|---|
| 10 * (1/0) | ZeroDivisionError | 0 で割った |
| 4 + spam*3(spam は未定義) | NameError | 定義していない名前を使った |
| '2' + 2 | TypeError | 文字列と整数は + でつなげない |
| int('3.5') | ValueError | 整数として読めない文字列 |
| {'a': 1}['b'] | KeyError | 辞書に無いキー |
| [1, 2][5] | IndexError | 範囲外のインデックス |
try 文と except 節
try と except:一致は派生クラスにも、動くのは最初の 1 つ
try 文は、まず try 節を実行します。例外が起きなければ except 節を飛ばして終わります。例外が起きると try 節の残りを飛ばし、型の一致する except 節を実行して、try 文の後へ進みます。
一致する except 節が無ければ、例外は外側の try 文に渡されます。どこでも処理されなければ未処理例外となり、メッセージを出して止まります。try 節から呼んだ関数の中で起きた例外も、呼び出し側の except 節で処理できます。
except 節はいくつでも書けますが、実行されるのは最大 1 つです。1 つの except 節で複数の例外を受けるときは、Python 3.9 では except (RuntimeError, TypeError, NameError): のように丸括弧のタプルで書きます。3.14 以降は括弧を省いた書き方も使えます。
except 節は、指定したクラスとその派生クラスの例外に一致します。上から最初に一致した節だけが動くので、基底クラスの節を先に書くと、派生クラスの節には届きません。派生クラスの節を先に並べます。
例外名を省いた except: は何でも受け止めるため、普通のプログラムの誤りを隠しやすい書き方です。受ける例外の型はなるべく具体的に書きます。
| except の並べ方(class B、C(B)、D(C)) | B・C・D を送出したときの表示 |
|---|---|
| except D → except C → except B | B、C、D |
| except B → except C → except D | B、B、B |
出典: Python チュートリアル 8.3 例外を処理する/Python チュートリアル 8.3 例外を処理する(Python 3.9)
例外の引数・else 節・Exception と BaseException
as と args、else 節、Exception と BaseException の違い
except 節に as 名前 を付けると、例外のインスタンスを受け取れます。例外に渡した引数は args 属性にタプルで入ります。raise Exception('spam', 'eggs') を受けた inst では、inst.args は ('spam', 'eggs') です。print(inst) でも引数が表示されます。
try 文の else 節は、すべての except 節の後に書き、try 節で例外が起きなかったときだけ実行されます。後の処理まで try 節に入れると、そこで起きた例外まで except 節で捕まえてしまいます。守りたい処理だけを try 節に置き、続きは else 節に書きます。
BaseException はすべての例外の基底クラスです。Exception はシステム終了以外の、ほぼすべての例外の基底クラスです。
KeyboardInterrupt(Ctrl-C などの割り込み)と SystemExit(sys.exit() で送出)は Exception を継承していません。そのため except Exception: では捕まりません。これらはプログラムを終わらせるための例外で、通常は処理しません。
| 節 | いつ動くか |
|---|---|
| try 節 | 最初に必ず実行される |
| except 節 | 型が一致する例外が起きたとき(最初の 1 つだけ) |
| try 文の else 節 | try 節で例外が起きなかったとき |
| finally 節 | 例外の有無にかかわらず、try 文を抜ける前に毎回 |
例外の送出と連鎖(raise・from)
raise と例外の連鎖:from で原因を示し、from None で隠す
raise 文は指定した例外を発生させます。渡せるのは例外のインスタンスか、BaseException を継承した例外クラスです。クラスを渡すと引数なしでインスタンス化されるので、raise ValueError は raise ValueError() の省略形です。
例外が起きたかを知りたいだけで処理はしないときは、except 節の中で引数なしの raise を書きます。処理中の例外がそのまま再送出され、呼び出し元でも処理できます。
except 節の中で別の例外が起きると、元の例外が自動で添えられます(例外の連鎖)。トレースバックには 2 つの例外が並び、間に During handling of the above exception, another exception occurred: と表示されます。
raise 新しい例外 from 元の例外 と書くと、元の例外が直接の原因だと示せます。例外を別の種類に変えるときに便利です。間の表示は The above exception was the direct cause of the following exception: になります。
from None と書くと連鎖が無効になり、表示されるのは新しい例外だけになります。
| except 節の中の書き方 | トレースバックの表示 |
|---|---|
| raise(引数なし) | 処理中の例外をそのまま再送出 |
| raise RuntimeError('x') | 元の例外+ During handling of the above exception... + RuntimeError |
| raise RuntimeError('x') from exc | 元の例外+ The above exception was the direct cause... + RuntimeError |
| raise RuntimeError from None | RuntimeError だけ |
ユーザー定義例外
ユーザー定義例外:Exception を継承し、名前は Error で終える
新しい例外クラスを作ると、アプリ独自のエラーを表せます。ユーザー定義例外は、通常 Exception を直接または間接に継承して作ります。BaseException を直接継承すると、except Exception: で捕まらなくなります。
名前は、標準の例外と同じく Error で終わるものが多いです。普通のクラスと同じことは何でもできますが、ハンドラが情報を取り出せる属性をいくつか持たせる程度の、単純なものにするのが普通です。
class AppError(Exception) と class DbError(AppError) のように階層を作ると、except AppError: で DbError も受け止められます。受け取ったインスタンスの型は DbError のままです。
クリーンアップ動作(finally 節)
finally 節:毎回動き、処理されなかった例外は後で再送出
finally 節は、例外の有無にかかわらず、try 文を抜ける前に毎回実行されます。ファイルやネットワーク接続など、外部の資源を後片付けするのに使います。
try 節の例外が except 節で処理されなかったときは、finally 節を実行した後でその例外が再送出されます。except 節や else 節の中で起きた例外も同じです。
try 節が break・continue・return に達すると、その文の直前に finally 節が実行されます。finally 節に return があると、try 節の return の値ではなく finally 節の値が返ります。finally 節で break・continue・return を実行すると、例外は再送出されません。 分かりにくい書き方なので勧められず、3.14 以降は SyntaxWarning が出ます。
チュートリアルの divide(x, y) の例では、divide(2, 1) は result is 2.0、divide(2, 0) は division by zero! の後に finally 節の表示になります。divide('2', '1') は TypeError が処理されないので、finally 節の表示の後に TypeError が送出されます。
| 呼び出し | 表示の順 |
|---|---|
| divide(2, 1) | result is 2.0 → executing finally clause |
| divide(2, 0) | division by zero! → executing finally clause |
| divide('2', '1') | executing finally clause → TypeError のトレースバック |
定義済みクリーンアップ処理(with 文)
with 文:使い終わったファイルを確実に閉じる
ファイルのように、使い終わったときの後始末が決まっているオブジェクトがあります。for line in open('myfile.txt'): と書くと、処理の後もファイルがいつ閉じられるか決まりません。小さなスクリプトでは問題になりにくいですが、大きなアプリでは問題になります。
with open('myfile.txt') as f: とwith 文で書くと、ブロックを抜けたとき、行の処理中に問題が起きた場合でもファイルが閉じられます。ファイルの with 文は例外を握りつぶさないので、中で起きた例外は外側の except 節に届きます。
演習(29 問)
結果はこのブラウザに保存され、ハブの「自分の成績」と弱点モードに使われます。
第 1 問 / 29 問
問題を読み込んでいます…
全問と解説の一覧
正解と解説は折りたたんであります。先に自分で考えてから開いてください。
全 29 問
構文エラー
対話モードで while True print('Hello') と入力すると SyntaxError になり、^ は print の位置を指した。直すべき点として最も適切なものは?
A. print の綴りを直す B. 'Hello' を二重引用符に変える C. True を小文字の true にする D. while True の後にコロン(:)を補う
この問題へのリンク答えと解説
正解: D 【A(不正解)】 ? 印が指している単語そのものを疑う考えです。 ^ は誤りを検出した位置で、そこが直す場所とは限らない。print の綴りに問題はない。 【B(不正解)】 ? 文字列の引用符の種類を変える考えです。 Python では単一引用符も二重引用符も同じように文字列を作れるので、原因ではない。 【C(不正解)】 ? 真偽値の書き方を変える考えです。 Python の真偽値は True と書く。小文字にすると別の名前になってしまう。 【D(正解)】 ? while 文の書き方の決まりに注目した考えです。 チュートリアルの例のとおり、原因は while True の後のコロンの抜け。パーサは次の print の位置で誤りを検出する。
構文エラーと例外の違いの説明として最も適切なものは?
A. 構文エラーは実行中に、例外はプログラムの解析中に見つかる B. 構文エラーは解析の段階で、例外は文法が正しくても実行中に見つかる C. どちらも、そのコードの中に書いた try 文で捕まえて処理を続けられる D. 例外は必ず致命的で、プログラムの中では処理できない
この問題へのリンク答えと解説
正解: B 【A(不正解)】 ? 見つかる段階を入れ替えた説明です。 実際は逆。構文エラーは解析(パース)の段階で、例外は実行中に検出される。 【B(正解)】 ? エラーが見つかる段階で区別した説明です。 SyntaxError は文法の誤りで解析中に見つかる。例外は構文が正しくても実行しようとしたときに起きる。 【C(不正解)】 ? どちらも同じように扱える、という説明です。 構文エラーのあるコードは実行前の解析で止まるので、同じコードの中の try 文は動かない。 【D(不正解)】 ? 例外の重さについての説明です。 チュートリアルは、例外は必ずしも致命的ではなく、プログラムで処理できると説明している。
次の内容の report.py を python report.py で実行した。画面に出るものとして最も適切なものは? print('start') x = 1 if x == 1 print(x)
A. start と表示された後に SyntaxError が出る B. start と 1 が表示される C. start は出ず、SyntaxError だけが出る D. start が表示された後に NameError が出る
この問題へのリンク答えと解説
正解: C 【A(不正解)】 ? 1 行目までは実行される、という考えです。 ファイルは実行の前に全体が解析される。3 行目で解析が失敗するので、1 行目の print も動かない。 【B(不正解)】 ? コロンが無くても動く、という考えです。 if 文の行末にコロンが無いのは文法の誤りなので、プログラムは動かない。 【C(正解)】 ? 実行より先に解析が行われる点に注目した考えです。 構文エラーは解析の段階で見つかるため、1 行も実行されない。ファイルから読んだときはファイル名と行番号も表示される。 【D(不正解)】 ? 実行中に名前が見つからない、という考えです。 x は定義されているので NameError にはならない。そもそも解析の段階で止まる。
例外とトレースバック
対話モードで 10 * (1/0) を実行した。発生する例外は?
A. ZeroDivisionError B. ValueError C. TypeError D. SyntaxError
この問題へのリンク答えと解説
正解: A 【A(正解)】 ? 0 で割ったときの例外です。 1/0 の割り算で ZeroDivisionError が発生する。メッセージの最後の行は ZeroDivisionError: division by zero になる。 【B(不正解)】 ? 型は合っているが、値の中身が使えないときの例外です。 0 での割り算には専用の例外があり、ValueError にはならない。 【C(不正解)】 ? 演算に合わない型を使ったときの例外です。 10 も 1 も 0 も整数で、型の組み合わせに問題はない。 【D(不正解)】 ? 文法に合わない書き方を表す例外です。 この式は文法として正しい。誤りは実行したときに見つかる。
入力された数字の文字列 '2' に数値 2 を足そうとして '2' + 2 と書いた。発生する例外は?
A. NameError B. TypeError C. ValueError D. 例外は起きず '22' になる
この問題へのリンク答えと解説
正解: B 【A(不正解)】 ? 定義されていない名前を使ったときの例外です。 この式には未定義の名前は出てこないので、NameError にはならない。 【B(正解)】 ? 演算に合わない型を組み合わせたときの例外です。 文字列と整数は + で連結できず TypeError になる。int('2') + 2 のように型をそろえる。 【C(不正解)】 ? 型は合っているが、値の中身が使えないときの例外です。 問題は値ではなく型の組み合わせにある。 【D(不正解)】 ? 数値を自動で文字列に変える、という考えです。 Python は文字列と数値を自動では変換しない。
未処理の例外でプログラムが止まり、エラーメッセージが出た。トレースバックの最後の行に表示されるものは?
A. Python のバージョン番号 B. 最初に呼び出した関数の名前だけ C. 例外の型と、何が起きたかの詳細 D. 直し方の候補の一覧
この問題へのリンク答えと解説
正解: C 【A(不正解)】 ? 使っているインタープリタの版の情報です。 エラーメッセージには Python のバージョンは表示されない。 【B(不正解)】 ? 呼び出しの始まりの情報です。 呼び出しの記録は最後の行より上に、スタックトレースバックとして表示される。 【C(正解)】 ? 例外の種類とその内容です。 最後の行は NameError: name 'spam' is not defined のように、例外の型と詳細を示す。 【D(不正解)】 ? 修正の案を並べたものです。 最後の行は例外の型と詳細を示す行。新しい版では名前の候補が添えられることもあるが、直し方の一覧ではない。
フォームに 3.5 と入力され、int('3.5') を実行した。発生する例外は?
A. TypeError B. ValueError C. 例外は起きず 3 になる D. ZeroDivisionError
この問題へのリンク答えと解説
正解: B 【A(不正解)】 ? 引数の型が合わないときの例外です。 int() は文字列を受け取れるので、型は合っている。 【B(正解)】 ? 型は合っているが中身が使えないときの例外です。 文字列は受け取れるが '3.5' は整数として読めない値なので ValueError になる。 【C(不正解)】 ? 小数点以下を切り捨てて変換する、という考えです。 int(3.5) のように数値なら 3 になるが、小数の形の文字列は整数に変換できない。 【D(不正解)】 ? 0 で割ったときの例外です。 この処理には割り算が無いので関係しない。
try 文と except 節
ValueError と TypeError のどちらが起きても、同じメッセージを出して処理したい。1 つの except 節で書く正しい形は?
A. except (ValueError, TypeError): B. except ValueError or TypeError: C. except [ValueError, TypeError]: D. except ValueError and TypeError:
この問題へのリンク答えと解説
正解: A 【A(正解)】 ? 丸括弧で例外をまとめる書き方です。 第4版(3.9)では、複数の例外を丸括弧で囲んだタプルで指定する。どちらが起きてもこの節が実行される。3.14 以降は括弧を省いても書ける。 【B(不正解)】 ? 論理演算子 or でつなぐ書き方です。 or は先に評価される ValueError だけを返すので、TypeError は捕まらない。 【C(不正解)】 ? 角括弧のリストでまとめる書き方です。 except に指定できるのは例外クラスかそのタプルで、リストは使えない。 【D(不正解)】 ? 論理演算子 and でつなぐ書き方です。 and は TypeError だけを返すので、ValueError は捕まらない。
出典: Python チュートリアル 8.3 例外を処理する(Python 3.9)/Python チュートリアル 8.3 例外を処理する(現行版)
class B(Exception)、class C(B)、class D(C) を定義した。B・C・D を順に送出し、except B、except C、except D の順に並べた節で受けた。各節は自分の名前を表示する。表示は?
A. B、C、D B. D、D、D C. B、B、B D. B、C の後に D が未処理例外になる
この問題へのリンク答えと解説
正解: C 【A(不正解)】 ? 送出したクラスと同じ名前の節が動く、という考えです。 except B は派生クラスの C や D にも一致する。最初に一致した節だけが実行されるので、こうはならない。 【B(不正解)】 ? 最も下の派生クラスの節が動く、という考えです。 except D は B や C のインスタンスには一致しない。しかも先に except B が一致する。 【C(正解)】 ? 最初に並べた節が派生クラスにも一致する、という考えです。 except 節は指定したクラスとその派生クラスに一致し、上から最初に一致した 1 つだけが動く。すべて except B で処理される。 【D(不正解)】 ? 最後の節まで届かない例外が出る、という考えです。 D は B の派生クラスなので except B に一致し、未処理にはならない。
関数の中の try 文で KeyError が起きたが、その try 文には except ValueError: しか無い。この例外はどうなる?
A. except ValueError: の節が代わりに実行される B. 外側の try 文に渡され、どこでも処理されなければ止まる C. 例外は消え、try 文の次の行から続く D. try 節の先頭からもう一度実行される
この問題へのリンク答えと解説
正解: B 【A(不正解)】 ? 近い節が代わりに受け止める、という考えです。 except 節は型が一致したときだけ動く。KeyError は ValueError の派生ではないので一致しない。 【B(正解)】 ? 呼び出し元へ順にさかのぼる、という考えです。 一致する節が無い例外は外側の try 文に渡される。最後まで処理されなければ未処理例外としてメッセージを出して止まる。 【C(不正解)】 ? 例外が無かったことになる、という考えです。 処理されなかった例外が黙って消えることはない。 【D(不正解)】 ? やり直しが自動で行われる、という考えです。 try 文に自動でやり直す仕組みは無い。やり直したいときは while 文などで自分で書く。
次のコードを実行した。表示されるものは? def this_fails(): x = 1/0 try: this_fails() except ZeroDivisionError as err: print('Handling:', err)
A. 何も表示されず、ZeroDivisionError で止まる B. Handling: ZeroDivisionError C. Handling: None D. Handling: division by zero
この問題へのリンク答えと解説
正解: D 【A(不正解)】 ? 関数の中の例外は外の try 文では捕まらない、という考えです。 ハンドラは try 節で呼んだ関数の中で起きた例外も処理する。止まらずに except 節が動く。 【B(不正解)】 ? 例外の型の名前が表示される、という考えです。 err を print すると型名ではなく、例外の詳細(引数)が表示される。 【C(不正解)】 ? 関数の戻り値が表示される、という考えです。 err は例外のインスタンスで、関数の戻り値ではない。 【D(正解)】 ? 例外の詳細のメッセージが表示される、という考えです。 関数の中で起きた例外も呼び出し側の except 節で処理される。err の表示は division by zero になる。
例外の引数・else 節・Exception と BaseException
次のコードを実行した。表示されるものは? try: raise Exception('spam', 'eggs') except Exception as inst: print(inst.args)
A. spam eggs B. ['spam', 'eggs'] C. ('spam', 'eggs') D. Exception
この問題へのリンク答えと解説
正解: C 【A(不正解)】 ? 引数を空白でつないだ表示です。 args は引数を並べたタプルなので、print すると丸括弧付きで表示される。 【B(不正解)】 ? 引数をリストにまとめた表示です。 args 属性はリストではなくタプルである。 【C(正解)】 ? 引数をタプルにまとめた表示です。 例外に渡した引数は args 属性にタプルで入る。x, y = inst.args のようにアンパックもできる。 【D(不正解)】 ? 例外の型の名前を表示したものです。 型を知りたいときは type(inst) を使う。args は引数を表す。
ファイルを開く処理だけを try 節に入れ、行数を数える処理は try 文の else 節に書いた。この書き分けの主な目的は?
A. else 節に書くと処理が速くなるから B. else 節は例外が起きたときだけ動くから C. else 節の処理は、例外の有無にかかわらず必ず動くから D. 守る範囲の外の例外まで except で捕まえないため
この問題へのリンク答えと解説
正解: D 【A(不正解)】 ? 実行の速さに注目した考えです。 else 節は速さのための仕組みではない。チュートリアルは捕まえる例外の範囲を理由に挙げている。 【B(不正解)】 ? else 節が動く条件についての考えです。 else 節は try 節で例外が起きなかったときに動く。例外が起きたときに動くのは except 節である。 【C(不正解)】 ? 後始末の節と同じ働きだという考えです。 必ず動くのは finally 節。else 節は try 節が例外なく終わったときだけ動く。 【D(正解)】 ? except 節が受け止める範囲に注目した考えです。 後の処理まで try 節に入れると、そこから出た例外まで except 節が捕まえてしまう。else 節に分けるとそれを防げる。
長い処理全体を try で囲み、except Exception: でエラーを記録している。実行中に Ctrl-C を押した場合の説明として最も適切なものは?
A. except Exception: で捕まえられ、記録の処理が動く B. Exception を継承しないので、この節では捕まらない C. Ctrl-C は例外ではないので、try 文とは関係なく終わる D. Ctrl-C は SyntaxError として扱われる
この問題へのリンク答えと解説
正解: B 【A(不正解)】 ? Exception がすべての例外の親だという考えです。 KeyboardInterrupt は Exception を継承していないので、この節には一致しない。 【B(正解)】 ? 例外クラスの継承関係に注目した考えです。 KeyboardInterrupt や SystemExit は BaseException から直接派生する。プログラムの終了に使う例外で、通常は処理しない。 【C(不正解)】 ? キー入力は例外の仕組みの外にある、という考えです。 チュートリアルによれば、利用者の割り込みは KeyboardInterrupt 例外の送出として通知される。 【D(不正解)】 ? 文法に合わない書き方として扱われる、という考えです。 割り込みは実行中の出来事で、文法の誤りとは関係ない。
try 文の else 節が実行されるのはどんなときか?
A. try 節で例外が起きなかったとき B. どの except 節にも一致しない例外が起きたとき C. except 節の処理が終わった直後 D. 例外の有無にかかわらず、毎回最後に
この問題へのリンク答えと解説
正解: A 【A(正解)】 ? try 節が最後まで無事に終わった場合です。 else 節はすべての except 節の後に書き、try 節で例外が起きなかったときに実行される。 【B(不正解)】 ? 受け止める節が見つからない場合です。 一致しない例外は外側へ渡される。else 節が受け止めることはない。 【C(不正解)】 ? 例外を処理した後の場合です。 例外が起きて except 節が動いたときは、else 節は実行されない。 【D(不正解)】 ? 必ず動く後始末の場合です。 毎回必ず動くのは finally 節の働きである。
例外の送出と連鎖(raise・from)
入力のチェックで raise ValueError と書いた。この書き方の意味として最も適切なものは?
A. ValueError を捕まえて、そのまま無視する B. クラスを渡すと SyntaxError になる C. raise ValueError() の省略形として扱われる D. 次に起きる ValueError をあらかじめ予約しておく
この問題へのリンク答えと解説
正解: C 【A(不正解)】 ? 例外を受け止める働きです。 例外を受け止めるのは except 節。raise 文は例外を発生させる。 【B(不正解)】 ? クラスは送出できない、という考えです。 raise には例外クラスも渡せる。文法の誤りにはならない。 【C(正解)】 ? クラスを渡したときの扱いです。 例外クラスを渡すと、引数なしでコンストラクタを呼んで暗黙にインスタンス化される。 【D(不正解)】 ? 後で発生させる準備をする、という考えです。 raise 文はその場で例外を発生させる。予約する仕組みではない。
except 節でエラーを記録した後、呼び出し元にも同じ例外を伝えたい。except 節の最後に書くものとして適切なものは?
A. return B. pass C. continue D. 引数なしの raise
この問題へのリンク答えと解説
正解: D 【A(不正解)】 ? 関数から戻る文です。 return すると例外は処理済みとなり、呼び出し元には伝わらない。 【B(不正解)】 ? 何もしない文です。 pass 文を書いても例外は処理済みのままで、呼び出し元には伝わらない。 【C(不正解)】 ? ループの次の回へ進む文です。 continue 文はループの中で使う文で、例外を伝える働きはない。 【D(正解)】 ? 処理中の例外をもう一度送り出す書き方です。 except 節の中で引数なしの raise 文を書くと、処理中の例外を再送出できる。
except ConnectionError as exc: の中で raise RuntimeError('Failed to open database') from exc を実行した。表示されるトレースバックの説明として適切なものは?
A. RuntimeError だけが表示され、ConnectionError は表示されない B. 2 つの例外の間に「上の例外が次の例外の直接の原因」という意味の 1 行が入る C. 2 つの例外の間に「上の例外を処理中に別の例外が起きた」という意味の 1 行が入る D. ConnectionError だけが表示され、RuntimeError は無視される
この問題へのリンク答えと解説
正解: B 【A(不正解)】 ? 元の例外が隠れる、という考えです。 元の例外が隠れるのは from None を使ったとき。from exc では両方が表示される。 【B(正解)】 ? 原因と結果の関係を示す表示です。 from で原因を明示すると、The above exception was the direct cause of the following exception: で 2 つの例外がつながる。 【C(不正解)】 ? 処理中に偶然起きたことを示す表示です。 During handling of the above exception... は from を書かずに except 節で別の例外が起きたときの表示である。 【D(不正解)】 ? 最初の例外だけが残る、という考えです。 送出したのは RuntimeError なので、最後に表示されるのは RuntimeError である。
内部の OSError を利用者向けの RuntimeError に置き換えて送出したい。元の例外はエラー表示に出したくない。適切な書き方は?
A. raise RuntimeError from None B. raise RuntimeError C. raise RuntimeError from OSError D. raise None from RuntimeError
この問題へのリンク答えと解説
正解: A 【A(正解)】 ? 連鎖の相手に None を指定する書き方です。 from None を使うと自動的な例外の連鎖が無効になり、表示は RuntimeError だけになる。 【B(不正解)】 ? from を付けずに送出する書き方です。 except 節の中で別の例外を送出すると自動で連鎖し、元の OSError も表示される。 【C(不正解)】 ? 元の例外のクラスを原因に指定する書き方です。 原因を明示する書き方なので、元の例外はむしろ表示される。 【D(不正解)】 ? 送出するものに None を指定する書き方です。 raise に渡せるのは例外のインスタンスかクラスで、None は送出できない。
except OSError: の中で、from を付けずに raise RuntimeError('unable to handle error') を実行した。どう扱われる?
A. 元の OSError は捨てられ、RuntimeError だけが残る B. RuntimeError は無視され、OSError が再送出される C. except 節の中では raise を書けないので SyntaxError になる D. 元の OSError が自動で添えられ、両方がトレースバックに表示される
この問題へのリンク答えと解説
正解: D 【A(不正解)】 ? 前の例外の情報が消える、という考えです。 except 節で新しい例外が起きると、元の例外が自動で添えられる。捨てられはしない。 【B(不正解)】 ? 前の例外が優先される、という考えです。 送出されるのは新しい RuntimeError で、元の OSError は添えられる側になる。 【C(不正解)】 ? 書ける場所の制限についての考えです。 except 節の中でも raise 文は書ける。 【D(正解)】 ? 前の例外が自動でつながる、という考えです。 except 節で別の例外が起きると自動で例外の連鎖になる。間に During handling of the above exception... が表示される。
ユーザー定義例外
自分のアプリ専用の例外クラスを作りたい。継承元として通常使うクラスは?
A. object B. Exception C. SyntaxError D. KeyboardInterrupt
この問題へのリンク答えと解説
正解: B 【A(不正解)】 ? すべてのクラスの大もとのクラスです。 例外として送出できるのは BaseException の派生だけ。object を直接継承したクラスは raise できない。 【B(正解)】 ? システム終了以外のほぼすべての例外の親クラスです。 ユーザー定義例外は通常、Exception を直接または間接に継承して作る。 【C(不正解)】 ? 文法に合わない書き方を表す例外です。 文法の誤りを表すクラスで、アプリのエラーを表す土台には向かない。 【D(不正解)】 ? 利用者の割り込みを表す例外です。 Exception の派生ではないので、継承すると except Exception: で捕まらなくなる。
在庫が足りないことを表す例外クラスを作る。チュートリアルが紹介する名前の付け方の慣習に沿ったものは?
A. StockShortage B. stock_shortage_exception C. OutOfStockError D. CheckStock
この問題へのリンク答えと解説
正解: C 【A(不正解)】 ? 状態をそのまま名詞で表した名前です。 クラスとしては作れるが、標準の例外の多くにならった語尾にはなっていない。 【B(不正解)】 ? 小文字と下線でつないだ名前です。 クラス名には通常この形を使わず、例外の語尾の慣習にも沿っていない。 【C(正解)】 ? 語尾に Error を付けた名前です。 多くの例外は標準の例外と同じく Error で終わる名前で定義される、とチュートリアルにある。 【D(不正解)】 ? 動作を表す動詞から始まる名前です。 動作を表す名前は関数向きで、例外の名前の慣習には沿っていない。
class AppError(Exception) と class DbError(AppError) を定義した。try 節で raise DbError('x') を実行し、except AppError as e: で受けた。どうなる?
A. except AppError の節で処理され、e は DbError のインスタンスになる B. except AppError の節で処理され、e は AppError に変換される C. 型が完全には一致しないので、未処理例外で止まる D. ユーザー定義例外は except で受けられず TypeError になる
この問題へのリンク答えと解説
正解: A 【A(正解)】 ? 親クラスの節が子クラスの例外も受け止める、という考えです。 except 節は指定したクラスの派生クラスにも一致する。e には送出した DbError のインスタンスが入る。 【B(不正解)】 ? 受け止めた節の型に合わせて変わる、という考えです。 例外のインスタンスは変換されない。type(e) は DbError のままである。 【C(不正解)】 ? クラス名が同じでないと一致しない、という考えです。 except 節は派生クラスにも一致するので、DbError は except AppError で捕まる。 【D(不正解)】 ? 自作の例外の扱いについての考えです。 ユーザー定義例外も組み込みの例外と同じように except 節で処理できる。
クリーンアップ動作(finally 節)
次の関数で divide(2, 0) を呼んだ。表示の順として適切なものは? def divide(x, y): try: result = x / y except ZeroDivisionError: print('division by zero!') else: print('result is', result) finally: print('executing finally clause')
A. division by zero! だけ B. executing finally clause の後に division by zero! C. division by zero! の後に executing finally clause D. division by zero!、result is、executing finally clause の 3 行
この問題へのリンク答えと解説
正解: C 【A(不正解)】 ? except 節だけが動く、という考えです。 finally 節は例外が処理された場合でも必ず実行される。 【B(不正解)】 ? finally 節が先に動く、という考えです。 finally 節は try 文を抜ける直前に動くので、except 節の後になる。 【C(正解)】 ? except 節の後に finally 節が動く、という考えです。 0 で割ると except 節が動き、else 節は飛ばされる。最後に finally 節が実行される。 【D(不正解)】 ? すべての節が順に動く、という考えです。 例外が起きたので else 節は実行されない。
次の関数 bool_return() の戻り値は? def bool_return(): try: return True finally: return False
A. True B. None C. SyntaxError になる D. False
この問題へのリンク答えと解説
正解: D 【A(不正解)】 ? try 節の return が先に決まる、という考えです。 finally 節に return があると、try 節の return の値ではなく finally 節の値が返る。 【B(不正解)】 ? 2 つの return が打ち消し合う、という考えです。 return が打ち消し合うことはない。finally 節の return の値が使われる。 【C(不正解)】 ? finally 節に return は書けない、という考えです。 finally 節にも return は書ける。ただし分かりにくいので勧められず、3.14 以降は SyntaxWarning が出る。 【D(正解)】 ? finally 節の return が使われる、という考えです。 try 節の return の直前に finally 節が実行され、そこに return があるとその値(False)が戻り値になる。
except ZeroDivisionError: と finally: だけを持つ try 文で、try 節の x / y に文字列どうしを渡し TypeError が起きた。どうなる?
A. finally 節は実行されず、すぐに TypeError で止まる B. finally 節が実行された後に TypeError が再送出される C. except ZeroDivisionError: の節が代わりに実行される D. finally 節が実行され、TypeError は消える
この問題へのリンク答えと解説
正解: B 【A(不正解)】 ? 処理されない例外では後始末が飛ばされる、という考えです。 finally 節は例外が処理されたかどうかにかかわらず実行される。 【B(正解)】 ? 後始末の後で例外が外へ出る、という考えです。 except 節で処理されなかった例外は、finally 節の実行後に再送出される。 【C(不正解)】 ? 近い種類の例外の節が受け止める、という考えです。 TypeError は ZeroDivisionError の派生ではないので、この節には一致しない。 【D(不正解)】 ? finally 節が例外を片付ける、という考えです。 finally 節は例外を処理しない。finally 節で return などを実行しない限り、例外は再送出される。
定義済みクリーンアップ処理(with 文)
ファイルを読む処理を with open('data.txt') as f: の中に書いた。この書き方の利点は?
A. ファイルの読み込みが速くなる B. ファイルが無いときに自動で作られる C. 途中で例外が起きても必ず閉じられる D. 中で起きた例外をすべて握りつぶしてくれる
この問題へのリンク答えと解説
正解: C 【A(不正解)】 ? 処理の速さについての利点です。 with 文の目的は後始末を確実にすることで、読み込みの速さとは関係がない。 【B(不正解)】 ? ファイルの作成についての利点です。 ファイルが作られるかどうかは open() の mode で決まる。with 文の働きではない。 【C(正解)】 ? 使い終わったファイルの後始末についての利点です。 with 文を抜けると、行の処理中に問題が起きても、ファイルは必ず閉じられる。 【D(不正解)】 ? 例外を表に出さない、という利点です。 ファイルの with 文は後始末をするだけで、例外は外へ伝わる。
for line in open('myfile.txt'): print(line, end='') と書いたら、レビューで直すよう言われた。チュートリアルが挙げる問題点は?
A. open() の戻り値は for 文で繰り返せない B. 処理が終わった後もファイルが開いたままになりうる C. end='' を付けると行が欠ける D. 1 行目が読み飛ばされる
この問題へのリンク答えと解説
正解: B 【A(不正解)】 ? ファイルを 1 行ずつ回せるかという点です。 ファイルオブジェクトは for 文で 1 行ずつ回せる。問題は別の点にある。 【B(正解)】 ? 使い終わったファイルの後始末の点です。 この書き方ではファイルを閉じる時期が決まっていない。大きなアプリでは問題になるので with 文を使う。 【C(不正解)】 ? print の区切りの点です。 各行の末尾には改行が残っているので、end='' は改行が二重にならないようにしているだけ。 【D(不正解)】 ? 読み始めの位置の点です。 for 文はファイルの先頭の行から順に読む。
with open('data.txt', encoding='utf-8') as g: のブロックの中で ValueError が起き、外側の try 文の except ValueError: で受けた。その時点の様子として適切なものは?
A. ファイルは開いたままで、g.closed は False B. with 文が例外を処理したので、外側の except 節は動かない C. ファイルは閉じられ、例外は外側の except 節で処理される D. ファイルを閉じる処理が失敗し、OSError に置き換わる
この問題へのリンク答えと解説
正解: C 【A(不正解)】 ? 例外で途中終了すると後始末が飛ぶ、という考えです。 with 文は途中で例外が起きてもファイルを閉じる。g.closed は True になる。 【B(不正解)】 ? with 文が例外を受け止める、という考えです。 ファイルの with 文は閉じる処理をするだけで、例外は外側へ伝わる。 【C(正解)】 ? ファイルは閉じられ、例外は外へ伝わる、という考えです。 with 文を抜けるときにファイルは閉じられ(g.closed は True)、ValueError は外側の except 節に届く。 【D(不正解)】 ? 後始末の段階で別の例外が起きる、という考えです。 読み込み用に開いたファイルを閉じても例外は置き換わらない。外側では ValueError として受けられる。
出典: Python チュートリアル 8.8 定義済みクリーンアップ処理/Python チュートリアル 7.2 ファイルを読み書きする
この分野に出てくる用語(30 語)
args 属性:例外を作るときに渡した引数を並べたタプル。except ... as e で受けた e.args で取り出せる。
BaseException:すべての組み込み例外の基底クラス。SystemExit や KeyboardInterrupt は Exception を継承していない。
continue 文:ループの残りの処理を飛ばして、次の繰り返しに進む文。
except 節:try 文で、指定した型の例外が起きたときに実行する部分。複数書けるが実行されるのは最初に一致した 1 つだけ。
Exception:システム終了以外の、ほぼすべての組み込み例外の基底クラス。ユーザー定義例外もこれを継承する。
finally 節:try 文の最後に、例外の有無にかかわらず必ず実行される部分。ファイルなど外部リソースの解放に使う。
IndexError:シーケンスの範囲外のインデックスを指定したときに発生する例外。
KeyboardInterrupt:利用者が Control-C などでプログラムを中断したときに発生する例外。Exception を継承していない。
KeyError:辞書に存在しないキーを指定したときに発生する例外。
NameError:定義されていない名前(変数など)を使ったときに発生する例外。
OSError:ファイルが見つからないなど、システムに関わるエラーで送出される例外。FileNotFoundError はその派生クラス。
pass 文:何もしない文。構文上は文が必要だが処理は要らないときや、書きかけのコードの仮置きに使う。
raise 文:指定した例外を発生させる文。except 節の中で引数なしの raise を書くと、その例外を再送出する。
RuntimeError:ほかのどの分類にも当てはまらないエラーが見つかったときに送出される例外。
SyntaxError:プログラムの解析中に見つかる文法の誤り。誤りを検出した行と位置が表示される。
SystemExit:sys.exit() を呼んだときに発生する例外。Exception を継承していない。
try 文:例外が起きそうな処理を try 節に書き、except 節で例外を処理する文。else 節や finally 節も付けられる。
try 文の else 節:すべての except 節の後に書き、try 節で例外が起きなかったときだけ実行される部分。守りたい処理以外の例外を誤って捕まえないために使う。
TypeError:演算や関数に不適切な型の値を渡したときに発生する例外。
ValueError:型は正しいが値が不適切なときに発生する例外。例えば無い値を list.remove() したとき。
with 文:ブロックを抜けるときに後始末を自動で行う文。ファイルは途中で例外が起きても確実に閉じられる。
ZeroDivisionError:0 で割ったときに発生する例外。
トレースバック:例外が起きたときに表示される、エラーに至るまでの呼び出しの記録。最後の行に例外の型と詳細が出る。
ファイルオブジェクト:open() が返すオブジェクト。read()・readline()・write() などのメソッドで読み書きする。
ユーザー定義例外:自分で作る例外クラス。通常は Exception を継承し、名前は Error で終えることが多い。
再送出:処理中の例外を、もう一度送り出して呼び出し元へ伝えること。except 節の中で引数なしの raise と書く。
真偽値:True(真)と False(偽)の値。0 や空のシーケンスは偽、0 以外の整数や長さ 1 以上のシーケンスは真として扱われる。
未処理例外:どの except 節でも処理されなかった例外。エラーメッセージとトレースバックを表示してプログラムが止まる。
例外:構文は正しいが、実行中に検出されるエラー。型によって種類が分かれ、処理しないとエラーメッセージを出して止まる。
例外の連鎖:ある例外が別の例外の原因になった関係。raise ... from ... で原因を明示でき、from None で連鎖を無効にできる。
独学の次に、講座で体系立てて学びたい人へ
この問題集は独学用です。IT の基礎から講師つきで体系立てて学びたい人には、資格や IT の講座がそろうスクールも選択肢になります。
本ページは広告・アフィリエイトプログラムを利用しており、リンク経由でのお申し込み・購入により当サイトに収益が発生することがあります。ただし、ランキング・評価・掲載内容は広告費や報酬の有無に関わらず編集部の独自基準で決定しており、広告主からの指示により内容を変更することはありません。
IT・Webデザイン・資格まで幅広い講座。生成AI/DX講座はリスキリング補助金の対象
まずは無料ではじめられます。リンク先は公式サイトです。
このサービスの解説記事を読む →