2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[Rust] PyO3でエラーを返す

Posted at

Rust で PyO3 を用いて Python 用ライブラリを作成していたのですが, ある関数の入力に関して制約があり (例えば平方根は入力が非負でなければいけない, のような), その制約を満たさない場合にエラー (ValueError) を返す方法がわからず手間取りました. 半年くらい後にきっとまた同じことをググる羽目になるんじゃないかと思いますが, それは面倒なのでわかったことをまとめておきます.

※本記事は Rust 1.45.2, PyO3 0.11.1 を使用して2020年8月に動作確認しました.

本論

こんな感じになると思います1.

#[pyfunction]
fn sqrt_rs(value: f64) -> PyResult<f64> {
    if value.is_sign_negative() {
        return Err(pyo3::exceptions::ValueError::py_err(
            "sqrtに負の値が入力されました. 非負の値を入力してください."
        );
    }

    Ok(value.sqrt())
}

他にも pyo3::exeptions に様々なエラー型が定義されています. 使い方はすべて同じで, py_err 関数を呼べば良いです.

解説

Python 側に露出する関数は Rust 側では PyResult<T> 型を返しますが, この型は何かというと PyResult<T> = Result<T, PyErr> です. ですからエラーが発生したら PyErr 型のインスタンスを生成し, Err で包んで return すればよさそうです. それで, PyErr 型ってなんでしょう?

PyO3 では Python の様々なエラー型 (ValueErrorTypeError など) をモジュール pyo3::exceptions 内で定義しています. これはすべて Rust 側でも異なる型なので, そのままでは扱いがやや面倒です. そこで PyO3 では様々なエラー型とその値を保持するラッパー構造体 PyErr を用意しています. 各エラー型には PyErr 型を返す py_err 関数が付随していて, これに引数としてその値を渡すことで欲しいエラー型インスタンスを包んだ PyErr インスタンスが取得できます.

参考文献

  1. これは例示のためのコードなので, NaN は? とか, if else を使えば return 不要, などの突っ込みを入れないでください.

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?