如何基于PyO3实现Python调用可接收Python函数作为参数的Rust函数
如何基于PyO3实现Python调用可接收Python函数作为参数的Rust函数
当然可以实现这种双向调用啦!我来一步步给你讲清楚怎么操作:
一、Rust端代码实现
首先我们要编写能接收Python函数参数并调用它的Rust代码,借助PyO3的PyFunction类型就能轻松实现:
use pyo3::prelude::*; use pyo3::types::PyFunction; // 标注这个函数可以被Python调用 #[pyfunction] fn my_rust_function(a: usize, f: &PyFunction) -> PyResult<usize> { // 调用传入的Python函数,将a作为位置参数传递 let py_result = f.call1((a,))?; // 将Python返回的对象转换为Rust的usize类型 py_result.extract() } // 定义Python模块,导出我们的函数 #[pymodule] fn rust_module(_py: Python<'_>, m: &PyModule) -> PyResult<()> { m.add_function(wrap_pyfunction!(my_rust_function, m)?)?; Ok(()) }
关键细节解释:
&PyFunction:PyO3提供的类型,用来表示传入的Python函数对象call1((a,)):调用Python函数的方法,call1接收一个元组作为位置参数,这里我们把a打包成单元素元组传递extract():负责把Python的返回值(比如int)转换成Rust对应的类型,这个操作会返回PyResult,用?可以自动将错误转换为Python异常抛出
二、Python端调用代码
接下来就可以在Python里调用这个Rust函数了,完全符合你预期的写法:
import rust_module def double(x): return 2*x def main(): # 调用Rust函数,传入数值3和我们定义的double函数 result = rust_module.my_rust_function(3, double) print(result) # 运行后会输出6 if __name__ == "__main__": main()
三、构建与运行
要让Python能导入Rust模块,推荐用maturin工具来构建:
- 先安装maturin:
pip install maturin - 进入你的Rust项目目录,执行
maturin develop,它会自动编译Rust代码并安装到当前Python环境中 - 之后就能直接运行上面的Python代码啦
额外注意事项:
- 如果需要处理关键字参数,可以使用
call方法代替call1,比如f.call((), Some(py_keyword_dict)) - 所有涉及Python对象的操作都需要持有GIL(全局解释器锁),不过
#[pyfunction]标注的函数被Python调用时,会自动持有GIL,无需额外处理 - 如果Python函数返回的类型和你要提取的Rust类型不匹配,
extract()会抛出Python异常,方便你调试
备注:内容来源于stack exchange,提问作者Red Rapious
相关产品推荐
相关产品推荐

