
本文档旨在解决在使用 PyO3 将 Python 嵌入 Rust 程序时,遇到的 ModuleNotFoundError 错误,尤其是在使用虚拟环境时。PyO3 默认使用全局 Python 安装,但通过手动初始化 Python 解释器并指定虚拟环境路径,可以确保 Rust 代码正确加载虚拟环境中的 Python 包。本文将提供详细的步骤和代码示例,帮助开发者正确配置 PyO3 和虚拟环境,解决依赖问题。
在使用 PyO3 将 Python 嵌入 Rust 程序时,可能会遇到一个常见问题:即使激活了虚拟环境并在其中安装了所需的 Python 包(例如 pyarrow),Rust 代码仍然无法找到这些包,并抛出 ModuleNotFoundError。这是因为 PyO3 默认情况下会使用全局 Python 安装,而不是虚拟环境。要解决这个问题,需要手动初始化 Python 解释器,并配置正确的虚拟环境路径。
以下是详细的步骤和代码示例:
禁用 auto-initialize 特性
立即学习“Python免费学习笔记(深入)”;
首先,需要在 Cargo.toml 文件中禁用 pyo3 的 auto-initialize 特性。这将允许我们手动初始化 Python 解释器。
[dependencies]pyo3 = { version = "0.20.0", features = [] } # 移除 "auto-initialize"polars = "0.35.4"pyo3-polars = "0.9.0"libc = "0.2.150"
手动初始化 Python 解释器
接下来,需要编写 Rust 代码来手动初始化 Python 解释器,并设置虚拟环境的路径。以下是一个示例函数:
use std::mem::size_of;use std::ptr::addr_of_mut;use libc::wchar_t;use pyo3::ffi::*;fn init_pyo3_with_venv(env_dir: &str) { unsafe { fn check_exception(status: PyStatus, config: &mut PyConfig) { unsafe { if PyStatus_Exception(status) != 0 { PyConfig_Clear(config); if PyStatus_IsExit(status) != 0 { std::process::exit(status.exitcode); } Py_ExitStatusException(status); } } } let mut config = std::mem::zeroed::(); PyConfig_InitPythonConfig(&mut config); config.install_signal_handlers = 0; // `wchar_t` is a mess. let env_dir_utf16; let env_dir_utf32; let env_dir_ptr; if size_of::() == size_of::() { env_dir_utf16 = env_dir .encode_utf16() .chain(std::iter::once(0)) .collect::<Vec>(); env_dir_ptr = env_dir_utf16.as_ptr().cast::(); } else if size_of::() == size_of::() { env_dir_utf32 = env_dir .chars() .chain(std::iter::once(' ')) .collect::<Vec>(); env_dir_ptr = env_dir_utf32.as_ptr().cast::(); } else { panic!("unknown encoding for `wchar_t`"); } check_exception( PyConfig_SetString( addr_of_mut!(config), addr_of_mut!(config.prefix), env_dir_ptr, ), &mut config, ); check_exception(Py_InitializeFromConfig(&config), &mut config); PyConfig_Clear(&mut config); PyEval_SaveThread(); }}
这个函数使用底层的 C API 来初始化 Python 解释器,并设置 prefix 属性为虚拟环境的路径。
在 main 函数中使用初始化函数
在 main 函数中,首先获取虚拟环境的路径,然后调用 init_pyo3_with_venv 函数来初始化 Python 解释器。
use polars::prelude::*;use pyo3::{prelude::*, types::PyModule};use pyo3_polars::PyDataFrame;fn main() -> PyResult { let env_dir = std::env::current_dir()?.join(".venv"); if !env_dir.is_dir() { panic!("please run from proper directory"); } init_pyo3_with_venv(env_dir.to_str().unwrap()); let code = include_str!("./test.py"); Python::with_gil(|py| { let activators = PyModule::from_code(py, code, "activators.py", "activators")?; let df: DataFrame = df!( "integer" => &[1, 2, 3, 4, 5], "float" => &[4.0, 5.0, 6.0, 7.0, 8.0], ) .unwrap(); let relu_result: PyDataFrame = activators .getattr("test")? .call1((PyDataFrame { 0: df },))? .extract()?; Ok(()) })}
在这个示例中,假设虚拟环境位于项目根目录下的 .venv 目录中。
Python 代码示例
以下是一个简单的 Python 代码示例,用于测试虚拟环境是否配置正确。
# test.pydef test(x): import sys print(sys.executable, sys.path, sys.prefix) import pyarrow # manipulate dataframe x return x
这个 Python 代码会打印 Python 解释器的路径、模块搜索路径和前缀,并尝试导入 pyarrow 模块。如果一切配置正确,pyarrow 应该能够成功导入。
注意事项:
确保在运行 Rust 代码之前,已经激活了虚拟环境,并在其中安装了所需的 Python 包。libc 依赖项是必需的,因为它提供了与底层 C API 交互的接口。wchar_t 的大小可能因平台而异,因此需要根据实际情况进行处理。此方法绕过了 PyO3 的自动初始化,因此需要手动处理 Python 解释器的初始化和清理。
总结:
通过手动初始化 Python 解释器并配置虚拟环境路径,可以解决在使用 PyO3 嵌入 Python 时遇到的 ModuleNotFoundError 错误。这种方法允许 Rust 代码正确加载虚拟环境中的 Python 包,并确保程序能够正常运行。虽然这种方法需要更多的手动配置,但它提供了更大的灵活性和控制权,特别是在处理复杂的依赖关系时。
以上就是使用 PyO3 嵌入 Python 解释器时配置虚拟环境的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1374946.html
微信扫一扫
支付宝扫一扫