PyO3のGitHubリポジトリーに上がっていた質問(issue 354)を参考にしたところ、うまくできたようです。
やり方ですが、pyfunction
な関数をPythonモジュールに入れ、それをPythonインタープリタの組み込み(built-in)モジュールとして登録します。登録にはPython C FFIの PyImport_AppendInittab
関数 を使います。
なお、参考にしたissueは2年前のものなので、そのままではコンパイルエラーになってしまいます。私の方で少し変更しましたが、もっといい方法があるかもしれません。(今日はじめてPyO3を触りました)
rust
1// Cargo.toml
2//
3// [dependencies]
4// pyo3 = "0.13.2"
5
6use std::ffi::CString;
7use pyo3::prelude::*;
8
9#[pyfunction]
10fn one() -> f32 {
11 1.
12}
13
14// one関数をmy_moduleモジュールに登録する
15// #[pymodule]により、モジュールを初期化するunsafeな関数
16// PyInit_my_moduleが生成される
17#[pymodule]
18fn my_module(_py: Python, m: &PyModule) -> PyResult<()> {
19 m.add_function(pyo3::wrap_pyfunction!(one, m)?)?;
20 Ok(())
21}
22
23// PyImport_AppendInittabはunsafeなモジュール初期化関数を
24// 受け付けないので、safeな関数でラップする
25extern "C" fn my_module_init() -> *mut pyo3::ffi::PyObject {
26 unsafe { PyInit_my_module() }
27}
28
29fn main() -> Result<(), Box<dyn std::error::Error>> {
30 //
31 // my_moduleをPythonインタープリタの組み込みモジュールとして登録する
32 //
33 let module_name = CString::new("my_module")?.into_raw();
34 unsafe {
35 pyo3::ffi::PyImport_AppendInittab(module_name, Some(my_module_init));
36 }
37
38 //
39 // Pythonインタープリタでmy_moduleからone関数をインポートし、実行する
40 //
41 let py_code = r#"
42from my_module import one
43print(one())
44"#;
45 let gil = Python::acquire_gil();
46 let py = gil.python();
47 py.run(py_code, None, None)?;
48 Ok(())
49}
環境
- Rust 1.51.0
- PyO3 0.13.2
- Python 3.8.8
- Linux x86_64 (NixOS)
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/04/25 01:15
2021/04/26 01:00