Rust与Python互操作库cpython的使用:实现Rust调用Python代码的高效桥梁
Rust与Python互操作库cpython的使用:实现Rust调用Python代码的高效桥梁
警告:这个包不再积极维护。请切换到PyO3。
这是Rust与Python解释器的绑定库。
支持的Python版本
- Python 2.7
- Python 3.7至3.12
需要Rust 1.41.1或更高版本。
使用方法
在Cargo.toml
中添加以下依赖:
[dependencies]
cpython = "0.7"
示例程序:显示sys.version
的值
use cpython::{Python, PyDict, PyResult};
fn main() {
let gil = Python::acquire_gil();
hello(gil.python()).unwrap();
}
fn hello(py: Python) -> PyResult<()> {
let sys = py.import("sys")?;
let version: String = sys.get(py, "version")?.extract(py)?;
let locals = PyDict::new(py);
locals.set_item(py, "os", py.import("os")?)?;
let user: String = py.eval("os.getenv('USER') or os.getenv('USERNAME')", None, Some(&locals))?.extract(py)?;
println!("Hello {}, I'm Python {}", user, version);
Ok(())
}
示例:带有Python绑定的库
以下两个文件可以使用cargo build
构建,并生成一个Python兼容的库。在Mac OS上,需要将输出从*.dylib重命名为*.so。在Windows上,需要将输出从*.dll重命名为*.pyd。
Cargo.toml:
[lib]
name = "rust2py"
crate-type = ["cdylib"]
[dependencies.cpython]
version = "0.7"
features = ["extension-module"]
src/lib.rs
use cpython::{PyResult, Python, py_module_initializer, py_fn};
// 为生成的Python模块添加绑定
// 注意:"rust2py"必须与.so或.pyd文件名相同
py_module_initializer!(rust2py, |py, m| {
m.add(py, "__doc__", "This module is implemented in Rust.")?;
m.add(py, "sum_as_string", py_fn!(py, sum_as_string_py(a: i64, b:i64)))?;
Ok(())
});
// 实现为普通Rust函数的逻辑
fn sum_as_string(a:i64, b:i64) -> String {
format!("{}", a + b).to_string()
}
// rust-cpython感知的函数。我们所有的Python接口都可以
// 声明在一个单独的模块中。
// 注意:py_fn!()宏会自动将参数从Python对象转换为Rust值;
// 并将Rust返回值转换回Python对象。
fn sum_as_string_py(_: Python, a:i64, b:i64) -> PyResult<String> {
let out = sum_as_string(a, b);
Ok(out)
}
在Windows和Linux上,可以使用cargo build --release
正常构建。在Mac OS上,需要设置额外的链接器参数。最简单的解决方案是创建一个.cargo/config
文件,内容如下:
[target.x86_64-apple-darwin]
rustflags = [
"-C", "link-arg=-undefined",
"-C", "link-arg=dynamic_lookup",
]
开发
要构建这个crate,运行:make build
要测试这个crate,运行:make test
注意:这个crate有几个文件是通过脚本自动生成的。使用Makefile可以确保这些文件根据需要重新生成。
完整示例
以下是一个更完整的示例,展示如何在Rust中调用Python函数:
use cpython::{Python, PyResult, PyDict};
fn main() {
let gil = Python::acquire_gil();
let py = gil.python();
// 导入Python模块
let sys = py.import("sys").unwrap();
// 获取Python版本
let version: String = sys.get(py, "version").unwrap().extract(py).unwrap();
println!("Python version: {}", version);
// 调用Python函数
let math = py.import("math").unwrap();
let result: f64 = math.call(py, "sqrt", (25.0,), None).unwrap().extract(py).unwrap();
println!("Square root of 25 is: {}", result);
// 使用Python字典
let dict = PyDict::new(py);
dict.set_item(py, "key1", "value1").unwrap();
dict.set_item(py, "key2", 42).unwrap();
// 执行Python代码
let locals = PyDict::new(py);
locals.set_item(py, "my_dict", dict).unwrap();
let code = "my_dict['key3'] = my_dict['key2'] * 2";
py.run(code, None, Some(&locals)).unwrap();
let key3: i32 = locals.get_item(py, "my_dict")
.unwrap()
.downcast_into::<PyDict>(py)
.unwrap()
.get_item(py, "key3")
.unwrap()
.extract(py)
.unwrap();
println!("key3 value: {}", key3);
}
这个示例展示了:
- 如何导入Python模块
- 如何获取Python对象的属性
- 如何调用Python函数
- 如何在Rust中创建和使用Python字典
- 如何执行Python代码并获取结果
注意:虽然cpython库仍然可以使用,但建议考虑使用更新的PyO3库进行Rust与Python的互操作。
1 回复