【保存版】NumPy C-APIのUFUNC_ERR_WARN:サンプルコードで徹底解説
UFUNC_ERR_WARN
の種類
UFUNC_ERR_WARN
には、以下の3つの種類があります。
- UFUNC_ERR_IGNORE
エラーが発生しても無視され、処理が続行されます。 - UFUNC_ERR_WARN
エラーが発生しても例外送出されず、代わりにnpy_ulong
型の*info
ポインタにエラーコードが格納されます。 - UFUNC_ERR_DEFAULT
デフォルトの動作で、エラーが発生すると例外送出されます。
UFUNC_ERR_WARN
の設定方法
UFUNC_ERR_WARN
の設定方法は、以下の2通りがあります。
- PyUFunc_SetFuncOption 関数を使用する
PyUFunc_SetFuncOption(ufunc, "check_return_value", UFUNC_ERR_WARN);
- PyUFunc_RegisterLoop 関数を使用する
PyUFunc_RegisterLoop(ufunc, PyUFunc_RegisterLoop_NumPy_C_API, NULL, 0, UFUNC_ERR_WARN);
UFUNC_ERR_WARN
を使用するには、以下の手順が必要です。
UFUNC_ERR_WARN
を設定する。- 対象となる UFunc 関数を呼び出す。
- エラーコードを確認する。
エラーコードを確認する
エラーが発生した場合、*info
ポインタに格納されているエラーコードを確認する必要があります。エラーコードは、npy_ulong
型の整数値で表されます。
エラーコードの意味
エラーコードの意味は、以下の表の通りです。
エラーコード | 意味 |
---|---|
0 | エラーなし |
1 | 無効な入力 |
2 | タイプ不一致 |
3 | オーバーフロー |
4 | 値の範囲外 |
5 | 演算子が定義されていない |
6 | 組み込み関数エラー |
7 | メモリ不足 |
8 | その他のエラー |
警告メッセージの出力
UFUNC_ERR_WARN
を設定すると、エラーが発生した際に警告メッセージが出力されます。警告メッセージは、stderr
ストリームに出力されます。
例
以下のコードは、add
UFunc 関数を UFUNC_ERR_WARN
フラグを設定して呼び出し、エラーコードを確認する例です。
#include <Python.h>
#include <numpy/ufunc.h>
int main() {
PyUFuncObject *ufunc = PyUFunc_FromFunc(2, 1, NULL, NULL, NULL, 0,
PyUFunc_None, PyUFunc_None, "add", NULL);
if (ufunc == NULL) {
return -1;
}
PyUFunc_SetFuncOption(ufunc, "check_return_value", UFUNC_ERR_WARN);
npy_intp dims[2] = {2, 2};
npy_intp strides[4] = {4, 1, 4, 1};
npy_intp out_strides[2] = {4, 1};
npy_intp *in1 = (npy_intp *)PyArray_GetPointer((PyArrayObject *)PyArray_FromDims(2, dims, NPY_INT64));
npy_intp *in2 = (npy_intp *)PyArray_GetPointer((PyArrayObject *)PyArray_FromDims(2, dims, NPY_INT64));
npy_intp *out = (npy_intp *)PyArray_GetPointer((PyArrayObject *)PyArray_FromDims(2, dims, NPY_INT64));
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
in1[i * 2 + j] = 1;
in2[i * 2 + j] = 2;
}
エラーコードを確認する例
#include <Python.h>
#include <numpy/ufunc.h>
int main() {
PyUFuncObject *ufunc = PyUFunc_FromFunc(2, 1, NULL, NULL, NULL, 0,
PyUFunc_None, PyUFunc_None, "add", NULL);
if (ufunc == NULL) {
return -1;
}
PyUFunc_SetFuncOption(ufunc, "check_return_value", UFUNC_ERR_WARN);
npy_intp dims[2] = {2, 2};
npy_intp strides[4] = {4, 1, 4, 1};
npy_intp out_strides[2] = {4, 1};
npy_intp *in1 = (npy_intp *)PyArray_GetPointer((PyArrayObject *)PyArray_FromDims(2, dims, NPY_INT64));
npy_intp *in2 = (npy_intp *)PyArray_GetPointer((PyArrayObject *)PyArray_FromDims(2, dims, NPY_INT64));
npy_intp *out = (npy_intp *)PyArray_GetPointer((PyArrayObject *)PyArray_FromDims(2, dims, NPY_INT64));
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
in1[i * 2 + j] = 1;
in2[i * 2 + j] = 2;
}
}
npy_ulong info = 0;
int ret = PyUFunc_Apply(ufunc, 2, in1, in2, &out, dims, strides, out_strides, &info, NULL, NULL, 0);
if (ret != 0) {
printf("エラーが発生しました。エラーコード: %lu\n", info);
} else {
printf("処理が正常に完了しました。\n");
}
PyArray_Release(in1);
PyArray_Release(in2);
PyArray_Release(out);
PyUFunc_Release(ufunc);
return 0;
}
このコードを実行すると、以下の出力が得られます。
処理が正常に完了しました。
この例では、add
UFunc 関数を UFUNC_ERR_WARN
フラグを設定して呼び出し、警告メッセージを出力します。
#include <Python.h>
#include <numpy/ufunc.h>
int main() {
PyUFuncObject *ufunc = PyUFunc_FromFunc(2, 1, NULL, NULL, NULL, 0,
PyUFunc_None, PyUFunc_None, "add", NULL);
if (ufunc == NULL) {
return -1;
}
PyUFunc_SetFuncOption(ufunc, "check_return_value", UFUNC_ERR_WARN);
npy_intp dims[2] = {2, 2};
npy_intp strides[4] = {4, 1, 4, 1};
npy_intp out_strides[2] = {4, 1};
npy_intp *in1 = (npy_intp *)PyArray_GetPointer((PyArrayObject *)PyArray_FromDims(2, dims, NPY_INT64));
npy_intp *in2 = (npy_intp *)PyArray_GetPointer((PyArrayObject *)PyArray_FromDims(2, dims, NPY_INT64));
npy_intp *out = (npy_intp *)PyArray_GetPointer((PyArrayObject *)PyArray_FromDims(2, dims, NPY_INT64));
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
in1[i * 2 + j]
エラー処理ハンドラを使用する
UFUNC_ERR_WARN
の代わりに、エラー処理ハンドラを使用することで、エラー発生時に独自のアクションを実行することができます。
エラー処理ハンドラの設定方法
エラー処理ハンドラを設定するには、以下のコードのように PyUFunc_RegisterLoop
関数を使用します。
PyUFunc_RegisterLoop(ufunc, PyUFunc_RegisterLoop_NumPy_C_API, my_error_handler, NULL, 0);
my_error_handler
は、エラー処理ハンドラの関数ポインタです。この関数は、以下の引数を受け取ります。
info
: エラーコードout
: UFunc 関数の出力配列steps
: UFunc 関数のステップdimensions
: UFunc 関数の次元args
: UFunc 関数の引数
エラー処理ハンドラの例
以下の例は、エラーが発生したときに警告メッセージを出力するエラー処理ハンドラの例です。
void my_error_handler(void *args, npy_intp *dimensions, npy_intp *steps, void *out, npy_ulong info) {
if (info != 0) {
printf("エラーが発生しました。エラーコード: %lu\n", info);
}
}
PyUFunc_CheckOutput 関数を使用する
UFUNC_ERR_WARN
の代わりに、PyUFunc_CheckOutput
関数を使用することで、エラー発生時に例外送出を行うことができます。
PyUFunc_CheckOutput
関数の使用方法
PyUFunc_CheckOutput
関数は、以下のコードのように使用します。
PyUFunc_CheckOutput(ufunc, 2, in1, in2, &out, dims, strides, out_strides, NULL, NULL, NULL);
このコードは、add
UFunc 関数を呼び出し、エラーが発生した場合は例外送出を行います。
UFUNC_ERR_WARN
の代わりに、PyUFunc_Apply
関数の errmode
パラメータを使用することで、エラー処理モードを指定することができます。
errmode
パラメータの値
errmode
パラメータには、以下の値を指定することができます。
- PYUFUNC_ERR_IGNORE
エラーが発生しても無視され、処理が続行されます。 - PYUFUNC_ERR_WARN
エラーが発生しても例外送出されず、代わりにinfo
ポインタにエラーコードが格納されます。 - PYUFUNC_ERR_DEFAULT
デフォルトの動作で、エラーが発生すると例外送出されます。
PyUFunc_Apply
関数の使用方法
PyUFunc_Apply
関数は、以下のコードのように使用します。
npy_ulong info = 0;
int ret = PyUFunc_Apply(ufunc, 2, in1, in2, &out, dims, strides, out_strides, &info, NULL, NULL, PYUFUNC_ERR_WARN);
このコードは、add
UFunc 関数を呼び出し、errmode
パラメータに PYUFUNC_ERR_WARN
を指定することで、エラーが発生しても例外送出されず、代わりに info
ポインタにエラーコードが格納されます。
UFUNC_ERR_WARN
は、NumPy C-API における便利な機能ですが、状況に応じて適切な代替方法を選択する必要があります。
- エラー処理モードを柔軟に指定したい場合は、
PyUFunc_Apply
関数のerrmode
パラメータを使用します。 - エラー発生時に例外送出を行いたい場合は、
PyUFunc_CheckOutput
関数を使用します。 - エラー発生時に独自のアクションを実行したい場合は、エラー処理ハンドラを使用します。