S-JIS[2025-12-13]

pyo3 0.27の例

Rustpyo3 0.27の例。


概要

PyO3 version 0.27を使って、Pythonから呼べるRustライブラリーを作る例。


maturinのインストール

PyO3を使ったRustライブラリーのプロジェクト作成にはmaturinを使うのが便利。

maturinをインストールするには、先にPythonをインストールおよびuvをインストールしておく。
maturin 1.10.2はPython 3.8以降に対応しているようだ。

uv tool install maturin
> uv run maturin --version
maturin 1.10.2

PyO3プロジェクトの作成

Windows11でPyO3を使うライブラリープロジェクトを作る例。

以下のコマンドで、example-pyo3という名前のRustプロジェクトを作成できる。
(生成されたCargo.tomlを見ると、pyo3のバージョンは0.27.0だった)

uv run maturin new example-pyo3

途中でどのライブラリーを使うか聞かれるので、pyo3を選ぶ。


以下のようなディレクトリーとファイルが生成される。


初期状態のlib.rsには以下のようなコードが書かれている。

example-pyo3/src/lib.rs:

use pyo3::prelude::*;

/// A Python module implemented in Rust.
#[pymodule]
mod example_pyo3 {
    use pyo3::prelude::*;

    /// Formats the sum of two numbers as string.
    #[pyfunction]
    fn sum_as_string(a: usize, b: usize) -> PyResult<String> {
        Ok((a + b).to_string())
    }
}

※古いバージョンのpyo3だと、pymoduleはfnで定義してpyfunctionをpyに登録する必要があったが、pyo3 0.27ではその手間が無くなっている。


初期生成されている雛形の関数は、以下のようにして実行することが出来る。

> cd example-pyo3
> uv run python
>>> import example_pyo3
>>> example_pyo3.sum_as_string(10, 5)
'15'

実行すると、初回は、Rustライブラリーがビルドされる。
また、venvのPython仮想環境が無い場合は自動的に作られる。


自動的にビルドする設定

デフォルトでは、src/lib.rsを更新してuv runしても反映されない(ビルドされない)。
この場合、--reinstallオプションを付けて実行すればいい。

uv run --reinstall python

ソースファイルを修正してuv runしたときに自動的にビルドされるようにするには、pyproject.tomlに以下の設定を追加する。

example-pyo3/pyproject.toml:

〜

[tool.uv]
cache-keys = [{ file = "pyproject.toml" }, { file = "src/**/*.rs" }, { file = "Cargo.toml" }, { file = "Cargo.lock" }]

こうしておけば、(--reinstallを付けなくても)ファイルの更新を検知して自動的にビルドしてくれる。


呼び出すPythonプロジェクトの作成

上記のRustプロジェクトの関数を呼び出すPythonプロジェクトを作成する例。

Rust用のexample-pyo3プロジェクトの隣に、Python用のcall-pyo3プロジェクトを作成する。

uv init --python 3.10 call-pyo3

以下のようなディレクトリーとファイルが生成される。


初期状態のmain.pyは以下のようになっている。

call-pyo3/main.py

def main():
    print("Hello from call-pyo3!")

if __name__ == "__main__":
    main()

以下のようにして実行できる。

cd call-pyo3
uv run main.py

venvのPython仮想環境が無い場合は自動的に作られる。


Rustライブラリーの呼び出し

Pythonのcall-pyo3プロジェクトから、Rustのexample-pyo3プロジェクトの関数を呼んでみる。


call-pyo3からexample-pyo3の関数を呼ぶ為には、example-poy3のライブラリーをインストールするか、依存ライブラリーに追加する必要がある。

が、それはさておき、example-pyo3の関数を呼ぶ実装は以下の通り。

call-pyo3/main.py:

import example_pyo3

def main():
    print("Hello from call-pyo3!")
    print(example_pyo3.sum_as_string(10, 5))

if __name__ == "__main__":
    main()

インストールする方法

example-pyo3のライブラリーをcall-pyo3にインストールする。

cd call-pyo3
uv pip install ../example-pyo3

※venvのPython仮想環境が作られていない場合はエラーになるので、その場合は「uv venv」でPython仮想環境を作成する。


これでmain.pyを実行すると、Rustで作った関数も呼ばれているのが確認できる。

> uv run main.py
Hello from call-pyo3!
15

依存ライブラリーに追加する方法

call-pyo3の依存ライブラリーにexample-pyo3を追加する。

cd call-pyo3
uv add ../example-pyo3

venvのPython仮想環境が無い場合は自動的に作られる。


上記のようにuv addを実行すると、pyproject.tomlに以下のような設定が追加される。

call-pyo3/pyproject.toml:

〜
dependencies = [
    "example-pyo3",
]

[tool.uv.sources]
example-pyo3 = { path = "../example-pyo3" }

これでmain.pyを実行すると、Rustで作った関数も呼ばれているのが確認できる。

> uv run main.py
Hello from call-pyo3!
15

なお、依存ライブラリーに追加する方法の場合、exmaple-pyo3側で[tool.uv]のcache-keysの設定をしておくと、example-pyo3のlib.rsを変更したら、uv run時に自動的に再ビルドされる。
(デフォルトでは、example-pyo3/pyproject.tomlファイルが更新されると、uv run時に再ビルドされるようだ)


グローバル定数

Pythonの定数はRustのconstで定義できる。

example-pyo3/src/lib.rs:

use pyo3::prelude::*;

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

    #[pymodule_export]
    const MY_VERSION: &str = "0.1.0";
}

call-pyo3/main.py:

import example_pyo3

def main():
    print(example_pyo3.MY_VERSION)

if __name__ == "__main__":
    main()

モジュール初期処理

モジュールの初期処理を行うには、#[pymodule_init]を付けた関数を用意する。

古いバージョンのPyO3のようにPyModuleを使って初期化したい場合にも利用できる。

例えばPythonの定数は以下のようにして定義することが出来る。

example-pyo3/src/lib.rs:

use pyo3::prelude::*;

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

    /// モジュール初期化時に呼ばれる
    #[pymodule_init]
    fn init(m: &Bound<'_, PyModule>) -> PyResult<()> {
        m.add("MY_VERSION", "0.1.0")?;
        Ok(())
    }
}

call-pyo3/main.py:

import example_pyo3

def main():
    print(example_pyo3.MY_VERSION)

if __name__ == "__main__":
    main()

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