S-JIS[2025-12-14/2026-02-23]

pyo3 Bound型

Rustpyo3のBoundのメモ。


概要

Boundは、pyo3 0.21で導入された構造体。

関数の引数としてPythonオブジェクトを受け取る場合は、従来のPy<T>よりBound<T>の方が良いらしい。
(Py<T>はポインターのようなものらしい)


use pyo3::prelude::*;

#[pymodule]
mod example_pyo3 {
    use pyo3::{prelude::*, types::*};

    #[pyfunction]
    fn my_function(arg1: &Bound<PyString>) -> PyResult<String> {
        let value: &str = arg1.extract()?;
        let result = format!("Hello, {}", value);
        Ok(result)
    }
}

Boundを引数で使う場合、&Bound<>でもBound<>でもいいようだが、基本的には&Boundにした方が良さそう。

Bound<T>からTのデータ型に変換するには、extractメソッドを使う。

例えばPyStringからは、&strやStringに変換することが出来る。


型の取得

Bound<PyAny>から、Pythonの型を取得することが出来る。[2026-01-20]

    #[pyfunction]
    fn type_check(arg: &Bound<PyAny>) -> PyResult<()> {
        let py_type = arg.get_type();   // Bound<PyType>
        let type_name = py_type.name()?; // Bound<PyString>
        println!("type_name: {}", type_name);

        Ok(())
    }

例えば、整数はint、浮動小数点はfloat、文字列はstr。


Py<T>からBound<T>への変換

従来のPy<T>からBound<T>に変換するにはbindまたはinto_pyobjectメソッドを使う。[/2025-12-16]

use pyo3::prelude::*;

#[pymodule]
mod example_pyo3 {
    use pyo3::{prelude::*, types::*};

    #[pyfunction]
    fn my_function2(py: Python, arg1: Py<PyString>) -> PyResult<String> {
        let arg1 = arg1.bind(py);            // &Bound<PyString>
//      let arg1 = arg1.into_pyobject(py)?; // Bound<PyString>
        let value: &str = arg1.extract()?;
        let result = format!("Hello, {}", value);
        Ok(result)
    }
}

bindやinto_pyobjectメソッドの引数にはpyが必要なので、関数の第1引数に「py: Python」を追加しておく必要がある。


Bound<T>からPy<T>への変換

Bound<T>からPy<T>へ変換するにはunbindメソッドを使う。

use pyo3::prelude::*;

#[pymodule]
mod example_pyo3 {
    use pyo3::{prelude::*, types::*};

    #[pyfunction]
    fn my_function3(py: Python, arg1: &str) -> PyResult<Py<PyString>> {
        let result = format!("Hello, {}", arg1);
        let bound_py_string = result.into_pyobject(py)?; // Bound<PyString>
        let py_py_string = bound_py_string.unbind();      // Py<PyString>
        Ok(py_py_string)
    }
}

StringからPyStringに変換するにもinto_pyobjectメソッドを使う。


Bound<T>からPy<T>へ変換するにはintoメソッドを使うことも出来る。

    #[pyfunction]
    fn my_function4(py: Python, arg1: &str) -> PyResult<Py<PyString>> {
        let result = format!("Hello, {}", arg1);
        let bound_py_string = result.into_pyobject(py)?; // Bound<PyString>
        Ok(bound_py_string.into())
    }

Bound<T>からPyRef<T>への変換

Tがpyclassによって自分で作ったクラスのとき、
Bound<T>からPyRef<T>へ変換するにはborrowメソッドを使う。[2026-02-23]
同様に、PyRefMut<T>へ変換するにはborrow_mutメソッドを使う。

PyRef<T>だと、Tの不変メソッドを呼び出すことが出来る。
PyRefMut<T>だと、Tの可変メソッドを呼び出すことが出来る。

    #[pyclass]
    struct MyClass3 {
        value: String,
    }

    #[pymethods]
    impl MyClass3 {
        #[new]
        fn new(value: String) -> Self {
            MyClass3 { value }
        }

        fn value(&self) -> &String {
            &self.value
        }

        fn set_value(&mut self, s: String) {
            self.value = s;
        }
    }
    #[pyfunction]
    fn print_my_class3(obj: &Bound<MyClass3>) -> PyResult<()> {
        let obj = obj.borrow(); // PyRef<MyClass3>
        println!("{}", obj.value());
    }

    #[pyfunction]
    fn update_my_class3(obj: &Bound<MyClass3>, s: String) {
        let mut value = obj.borrow_mut(); // PyRefMut<MyClass3>
        value.set_value(s);
    }

まぁ、引数で直接PyRefやPyRefMutを受け取ることも出来るのだが。

    #[pyfunction]
    fn print_my_class3_ref(obj: PyRef<MyClass3>) {
        println!("{}", obj.value());
    }

    #[pyfunction]
    fn update_my_class3_ref(mut obj: PyRefMut<MyClass3>, s: String) {
        obj.set_value(s);
    }

Bound<PyAny>の場合はborrowメソッドは無く、extractメソッドでPyRefに変換する。

Bound<PyDict>の場合もborrowメソッドが無いが、直接PyDictのメソッドが呼べる。(Derefが実装されているらしい)


Bound<T>を返す例

Bound<T>を返す場合は、ライフタイムを明示する(必要があることがある)。[2026-02-04]

    #[pyfunction]
    fn my_function5<'py>(py: Python<'py>, arg1: &str) -> PyResult<Bound<'py, PyString>> {
        let result = format!("Hello, {}", arg1);
        let bound_py_string = result.into_pyobject(py)?; // Bound<PyString>
        Ok(bound_py_string)
    }

Boundの定義は、厳密にはBound<'py, T>である。(Rustでは、書かなくて済む場面ではライフタイム(今回は'py)を省略できる)

Bound<T>のインスタンスを生成する場合、py: Python(Python構造体のオブジェクト)が使われる。
Python構造体もライフタイムを持っており、厳密にはPython<'py>である。

Boundのライフタイム(生存期間)はPythonのライフタイム以下なので、 メソッドや関数の返り値の型として使う場合はPythonと同じライフタイムを指定する。


pyo3へ戻る / Rustへ戻る / 技術メモへ戻る
メールの送信先:ひしだま