#
4. 例外処理

この章で説明する関数を使うと、Pythonの例外の処理や送出ができるように なります。Pythonの例外処理の基本をいくらか理解することが大切です。 例外はUnix `errno`変数にやや似た機能を果たします: 発生した 中で最も新しいエラーの(スレッド毎の)グローバルなインジケータがあります。 実行に成功した場合にはほとんどの関数がこれをクリアしませんが、失敗したときには エラーの原因を示すために設定します。ほとんどの関数はエラーインジケータも 返し、通常は関数がポインタを返すことになっている場合は`NULL`であり、 関数が整数を返す場合は`-1`です。(例外: `PyArg_*()`関数は 実行に成功したときに`1`を返し、失敗したときに`0`を返します).

ある関数が呼び出した関数がいくつか失敗したために、その関数が失敗しなければ ならないとき、一般的にエラーインジケータを設定しません。呼び出した関数が すでに設定しています。エラーを処理して例外をクリアするか、あるいは (オブジェクト参照またはメモリ割り当てのような)それが持つどんなリソースも 取り除いた後に戻るかのどちらか一方を行う責任があります。エラーを処理する 準備をしていなければ、普通に続けるべきではありません。エラーのために 戻る場合は、エラーが設定されていると呼び出し元に知らせることが大切です。 エラーが処理されていない場合または丁寧に伝えられている場合には、 Python/C APIのさらなる呼び出しは意図した通りには動かない可能性があり、 不可解な形で失敗するかもしれません。

エラーインジケータはPython変数`sys.exc_type`, `sys.exc_value` および `sys.exc_traceback`に対応する三つのPythonオブジェクトからからなります。 いろいろな方法でエラーインジケータとやりとりするためにAPI関数が存在します。 各スレッドに別々のエラーインジケータがあります。

void `PyErr_Print`( | )

  `sys.stderr`へ標準トレースバックをプリントし、エラーインジケータを クリアします。エラーインジケータが設定されているときにだけ、この関数を 呼び出してください。(それ以外の場合、致命的なエラーを引き起こすでしょう!)

PyObject* `PyErr_Occurred`( | )

  戻り値: 借りた参照.
  エラーインジケータが設定されているかテストします。設定されている場合は、 例外の型(`PyErr_Set*()`関数の一つあるいは `PyErr_Restore()`への最も新しい呼び出しに対する第一引数)を返します。 設定されていない場合は`NULL`を返します。あなたは戻り値への参照を持っていませんので、 それに`Py_DECREF()`する必要はありません。注意: 戻り値を特定の例外と 比較しないでください。その代わり、下に示す`PyErr_ExceptionMatches()`を 使ってください。(比較は簡単に失敗するでしょう。なぜなら、例外はクラスではなく インスタンスかもしれないし、あるいは、クラス例外の場合は期待される例外の サブクラスかもしれないからです。)

int `PyErr_ExceptionMatches`( | PyObject *exc)

  "`PyErr_GivenExceptionMatches(PyErr_Occurred(), exc)`"と同じ。 例外が実際に設定されたときにだけ、これを呼び出だすべきです。例外が発生 していないならば、メモリアクセス違反が起きるでしょう。

int `PyErr_GivenExceptionMatches`( | PyObject *given, PyObject *exc)

  given例外がexcの例外と一致するなら真を返します。これはexcが クラスオブジェクトである場合も真を返します。これはgivenがサブクラスの インスタンスであるときも真を返します。excがタプルならば、タプル内 (と再帰的にサブタプル内)のすべての例外が一致するか調べられます。 givenが`NULL`ならば、メモリアクセス違反が起きるでしょう。

void `PyErr_NormalizeException`( | PyObject**exc, PyObject**val, PyObject**tb)

  ある状況では、以下の`PyErr_Fetch()`が返す値は ``正規化されていない''可能性があります。つまり、`*exc`は クラスオブジェクトだが`*val`は同じクラスのインスタンスでは ないという意味です。この関数はそのような場合にそのクラスをインスタンス化 するために使われます。その値がすでに正規化されている場合は何も起きません。 遅延正規化はパフォーマンスを改善するために実装されています。

void `PyErr_Clear`( | )

  エラーインジケータをクリアします。エラーインジケータが設定されていないならば、 効果はありません。

void `PyErr_Fetch`( | PyObject **ptype, PyObject **pvalue, PyObject **ptraceback)

  エラーインジケータをアドレスを渡す三つの変数の中へ取り出します。 エラーインジケータが設定されていない場合は、三つすべての変数を`NULL`に 設定します。エラーインジケータが設定されている場合はクリアされ、 あなたは取り出されたそれぞれのオブジェクトへの参照を持つことになります。 型オブジェクトが`NULL`でないときでさえ、その値とトレースバックオブジェクトは `NULL`かもしれません。注意: 通常、この関数は例外を扱う必要のあるコード あるいはエラーインジケータを一時的に保存して元に戻す必要のあるコードに よってのみ使用されます。

void `PyErr_Restore`( | PyObject *type, PyObject *value, PyObject *traceback)

  三つのオブジェクトからエラーインジケータを設定します。エラーインジケータが すでに設定されている場合は、最初にクリアされます。オブジェクトが`NULL`ならば、 エラーインジケータがクリアされます。`NULL`のtypeと非`NULL`のvalueあるいは tracebackを渡してはいけません。例外の型(type)はクラスであるべきです。 無効な例外の型(type)あるいは値(value)を渡してはいけません。 (これらの規則を破ると後で気付きにくい問題の原因となるでしょう。) この呼び出しはそれぞれのオブジェクトへの参照を取り除きます: あなたは 呼び出しの前にそれぞれのオブジェクトへの参照を持たなければならないのであり、 また呼び出しの後にはもはやこれらの参照を持っていません。 (これを理解していない場合は、この関数を使ってはいけません。注意しておきます。) 注意: 通常この関数はエラーインジケータを一時的に保存し元に戻す必要のある コードによってのみに使われます。現在の例外状態を保存するためには `PyErr_Fetch()`を使ってください。

void `PyErr_SetString`( | PyObject *type, char *message)

  これはエラーインジケータを設定するための最も一般的な方法です。第一引数は 例外の型を指定します。通常は標準例外の一つ、例えば`PyExc_RuntimeError`です。 その参照カウントを増加させる必要はありません。第二引数はエラーメッセージで、 文字列オブジェクトへ変換されます。

void `PyErr_SetObject`( | PyObject *type, PyObject *value)

  この関数は`PyErr_SetString()`に似ていますが、 例外の``値(value)''として任意のPythonオブジェクトを指定することができます。

PyObject* `PyErr_Format`( | PyObject *exception, const char *format, ...)

  戻り値: 常に `NULL`.
  この関数はエラーインジケータを設定し`NULL`を返します。 exceptionはPython例外(インスタンスではなくクラス)であるべきです。 formatは文字列であるべきであり、`printf()`に似た 書式化コードを含んでいます。書式化コードの前の`幅.精度(width.precision)`は 解析されますが、幅の部分は無視されます。

  文字 | 意味
  --- | ---
  `c` | 文字、`int`引数として
  `d` | 10進数、`int`引数として
  `x` | 16進数、`int`引数として
  `s` | 文字列、`char *`引数として
  `p` | 16進法のポインタ、`void *`引数として

  認識できない書式化文字があると書式化文字列の残りすべてがそのまま 結果の文字列へコピーされ、余分の引数はどれも捨てられます。

void `PyErr_SetNone`( | PyObject *type)

  これは"`PyErr_SetObject(type, Py_None)`"を省略したものです。

int `PyErr_BadArgument`( | )

  これは"`PyErr_SetString(PyExc_TypeError, message)`"を省略したもので、 ここでmessageは組み込み操作が不正な引数で呼び出されたということを表しています。 主に内部で使用するためのものです。

PyObject* `PyErr_NoMemory`( | )

  戻り値: 常に `NULL`.
  これは"`PyErr_SetNone(PyExc_MemoryError)`"を省略したもので、 `NULL`を返します。したがって、メモリ不足になったとき、 オブジェクト割り当て関数は"`return PyErr_NoMemory();`"と 書くことができます。

PyObject* `PyErr_SetFromErrno`( | PyObject *type)

  戻り値: 常に `NULL`.
  Cライブラリ関数がエラーを返してC変数`errno`を設定したときに、 これは例外を発生させるために便利な関数です。第一要素が 整数`errno`値で、第二要素が (`strerror()`から得られる)対応する エラーメッセージであるタプルオブジェクトを構成します。それから、 "`PyErr_SetObject(type, object)`"を呼び出します。 Unixでは、`errno`値が`EINTR`であるとき、すなわち 割り込まれたシステムコールを表しているとき、これは `PyErr_CheckSignals()`を呼び出し、それがエラーインジケータを 設定した場合は設定されたままにしておきます。関数は常に`NULL`を返します。 したがって、システムコールがエラーを返したとき、システムコールの ラッパー関数は"`return PyErr_SetFromErrno(type);`"と 書くことができます。

PyObject* `PyErr_SetFromErrnoWithFilename`( | PyObject *type, char *filename)

  戻り値: 常に `NULL`.
  `PyErr_SetFromErrno()`に似ていて、filenameが`NULL`でない場合に、 それがtypeのコンストラクタに第三引数として渡されるというふるまいが追加 されています。`IOError`と`OSError`のような例外の場合では、 これが例外インスタンスの`filename`属性を定義するために使われます。

PyObject* `PyErr_SetFromWindowsErr`( | int ierr)

  戻り値: 常に `NULL`.
  これは`WindowsError`を発生させるために便利な関数です。 `0`のierrとともに呼び出された場合、`GetLastError()`が 返すエラーコードが代りに使われます。ierrあるいは `GetLastError()`によって与えられるエラーコードのWindows用の説明を 取り出すために、Win32関数`FormatMessage()`を呼び出します。それから、 第一要素がierr値で第二要素が(`FormatMessage()`から得られる) 対応するエラーメッセージであるタプルオブジェクトを構成します。そして、 "`PyErr_SetObject(PyExc_WindowsError, object)`"を呼び出します。 この関数は常に`NULL`を返します。 利用可能範囲: Windows。

PyObject* `PyErr_SetExcFromWindowsErr`( | PyObject *type, int ierr)

  `PyErr_SetFromWindowsErr()`に似ていて、送出する例外の型を 指定する引数が追加されています。 利用可能範囲: Windows。 バージョン2.3 以降で新規追加された 仕様です。

PyObject* `PyErr_SetFromWindowsErrWithFilename`( | int ierr, char *filename)

  戻り値: 常に `NULL`.
  `PyErr_SetFromWindowsErr()`に似ていて、filenameが`NULL`でない場合には `WindowsError`のコンストラクタへ第三引数として渡されるという振る舞いが 追加されています。 利用可能範囲: Windows。

PyObject* `PyErr_SetExcFromWindowsErrWithFilename`( | PyObject *type, int ierr, char *filename)

  `PyErr_SetFromWindowsErrWithFilename()`に似ていて、 発生させる例外の型を指定する引数が追加されています。 利用可能範囲: Windows。 バージョン2.3 以降で新規追加された 仕様です。

void `PyErr_BadInternalCall`( | )

  "`PyErr_SetString(PyExc_TypeError, message)`"を省略したものです。 ここでmessageは内部操作(例えば、Python/C API関数)が不正な引数と ともに呼び出されたということを示しています。主に内部で使用するためのもの です。

int `PyErr_Warn`( | PyObject *category, char *message)

  警告メッセージを出します。category引数は警告カテゴリ(以下を参照) かまたは`NULL`で、message引数はメッセージ文字列です。

  この関数は通常警告メッセージをsys.stderrへプリントします。 けれども、ユーザが警告をエラーへ変更するように指定することも可能です。 そのような場合には、これは例外を発生させます。警告機構がもつ問題のために その関数が例外を発生させるということも可能です。(実装ではその厄介な仕事を 行うために`warnings`モジュールをインポートします)。 例外が発生させられなければ、戻り値は`0`です。あるいは、例外が発生させ られると`-1`です。(警告メッセージが実際にプリントされるかどうかを決定 することはできず、また何がその例外の原因なのかを決定することもできない。 これは意図的なものです。)例外が発生した場合、呼び出し元は通常の例外処理を 行います(例えば、`Py_DECREF()`は参照を持っており、エラー値を 返します)。

  警告カテゴリは`Warning`のサブクラスでなければならない。 デフォルト警告カテゴリは`RuntimeWarning`です。 標準Python警告カテゴリは"`PyExc_`"にPython例外名が続く名前の グローバル変数を用いて変更できます。これらは型`PyObject*`を 持ち、すべてクラスオブジェクトです。それらの名前は `PyExc_Warning`, `PyExc_UserWarning`, `PyExc_DeprecationWarning`, `PyExc_SyntaxWarning`, `PyExc_RuntimeWarning`および`PyExc_FutureWarning`です。 `PyExc_Warning`は`PyExc_Exception`のサブクラスです。 その他の警告カテゴリは`PyExc_Warning`のサブクラスです。

  警告をコントロールするための情報については、`warnings`モジュールの ドキュメンテーションとコマンドライン・ドキュメンテーションの -Wオプションを参照してください。 警告コントロールのためのC APIはありません。

int `PyErr_WarnExplicit`( | PyObject *category, char *message, char *filename, int lineno, char *module, PyObject *registry)

  すべての警告の属性を明示的に制御した警告メッセージを出します。 これはPython関数`warnings.warn_explicit()`の直接的なラッパで、 さらに情報を得るにはそちらを参照してください。そこに説明されているデフォルトの 効果を得るために、moduleとregistry引数は`NULL`に設定できます。

int `PyErr_CheckSignals`( | )

  この関数はPythonのシグナル処理とやりとりすることができます。 シグナルがそのプロセスへ送られたかどうかチェックし、そうならば対応する シグナルハンドラを呼び出します。 `signal` モジュールがサポートされている場合は、 これはPythonで書かれたシグナルハンドラを呼び出せます。すべての場合で、 `SIGINT` のデフォルトの効果は `KeyboardInterrupt`例外を発生させることです。例外が発生した場合、 エラーインジケータが設定され、関数は`1`を返します。 そうでなければ、関数は`0`を返します。エラーインジケータが以前に 設定されている場合は、それがクリアされるかどうかわかりません。

void `PyErr_SetInterrupt`( | )

  `SIGINT` シグナルが 到達した影響をシミュレートします -- 次に `PyErr_CheckSignals()`が呼ばれるとき、 `KeyboardInterrupt`は送出されるでしょう。インタプリタロックを 保持することなく呼び出せます。

PyObject* `PyErr_NewException`( | char *name, PyObject *base, PyObject *dict)

  戻り値: 新たな参照.
  このユーティリティ関数は新しい例外オブジェクトを作成して返します。 name引数は新しい例外の名前、`module.class`形式の C文字列でなければなりません。 baseとdict引数は通常`NULL`です。これはすべての例外のためのルート、 組み込み名`Exception`(Cでは`PyExc_Exception`としてアクセス可能) から導出されたクラスオブジェクトを作成します。 新しいクラスの`__module__`属性はname引数の前半部分(最後のドットまで)に 設定され、クラス名は後半部分(最後のドットの後)に設定されます。 base引数は代わりのベースクラスを指定するために使えます。 dict引数はクラス変数とメソッドの辞書を指定するために使えます。

void `PyErr_WriteUnraisable`( | PyObject *obj)

  例外が設定されているがインタプリタが実際に例外を発生させることができないときに、 このユーティリティ関数は警告メッセージを`sys.stderr`へプリントします。 例えば、例外が`__del__()`メソッドで発生したときに使われます。

  発生させられない例外が生じたコンテキストを特定するための一つの引数objとともに 関数が呼び出されます。objのreprが警告メッセージにプリントされるでしょう。