微软的一位大牛,在Github上开发了一个Rust模块,名为PyO3。这个模块是Python的Rust绑定,通过它可以实现Rust与Python的混合编程。在这个项目开始的时候,还有一个功能类似的模块叫做rust_cpython,在当时是名气很大的一个项目,后来,rust_cpython的开发者也加入了PyO3项目,PyO3项目吸收了rust_cpython后变得十分强大,它可以在Rust中调用Python的模块,以弥补Rust库的还不足的现实问题,也可以将Rust直接编译成Python的模块,实现为Python加速的目的。

项目的GitHub地址为:https://github.com/PyO3/pyo3。此外,围绕着这个项目,还有一系列周边项目:

Rust调用Python

在没有进行实际的项目时,不太容易想象Rust在哪里需要调用Python来实现某些功能。这里先用PyO3中的例子来学习一下,知道有这种可能,将来遇到用Rust解决实际问题比较困难的时候,可以将此列为一个选项。

官方的例子是调用Python的sys模块来读取Python的版本号,和使用Python的os模块来读取环境变量:

  1. 首先使用cargo生成一个可执行的项目:
  1. cargo new rust_python
  1. 在生成的Cargo.toml中的dependencies中添加pyo3依赖:
  1. [dependencies]
  2. pyo3=""
  1. 在生成的main.rs中的编写如下代码:
  1. use pyo3::prelude::*;
  2. use pyo3::types::IntoPyDict;
  3. fn main() -> Result<(), ()> {
  4. Python::with_gil(|py| {
  5. main_(py).map_err(|e| {
  6. // We can't display Python exceptions via std::fmt::Display,
  7. // so print the error here manually.
  8. e.print_and_set_sys_last_vars(py);
  9. })
  10. })
  11. }
  12. fn main_(py: Python) -> PyResult<()> {
  13. // 导入sys模块
  14. let sys = py.import("sys")?;
  15. // 从调用sys.verson取得Python版本
  16. let version: String = sys.get("version")?.extract()?;
  17. // 将os模块导入本地变量字典
  18. let locals = [("os", py.import("os")?)].into_py_dict(py);
  19. // 以字符串的形式编写Python代码
  20. let code = "os.getenv('USER') or os.getenv('USERNAME') or 'Unknown'";
  21. // 使用Python的eval函数执行Python代码
  22. let user: String = py.eval(code, None, Some(&locals))?.extract()?;
  23. println!("Hello {}, I'm Python {}", user, version);
  24. Ok(())
  25. }

Python调用Rust