29 个版本
0.22.2 | 2024年7月17日 |
---|---|
0.22.0 | 2024年6月24日 |
0.21.0 | 2024年3月25日 |
0.20.1 | 2023年12月30日 |
0.16.2 | 2022年3月15日 |
176 在 FFI 中
每月下载量 2,933,081
用于 864 个 crate(直接使用 3 个)
365KB
8K SLoC
pyo3-ffi
此crate提供了Python 3的Rust FFI声明。它通过使用cfg标志支持ABI的稳定和不稳定组件。支持Python版本3.7及以上。仅适用于高级用户 - 定期使用PyO3的用户根本不需要与这个crate进行交互。
此crate的内容在此处没有文档说明,因为这基本上涉及从CPython复制文档。请参阅Python/C API参考手册以获取最新文档。
最低支持的Rust和Python版本
PyO3支持以下软件版本
- Python 3.7及以上(CPython和PyPy)
- Rust 1.63及以上
示例:构建Python本地模块
PyO3可用于生成原生Python模块。第一次尝试此功能的最简单方法是使用maturin
。 maturin
是一个用于使用最小配置构建和发布基于Rust的Python包的工具。以下步骤为示例Python模块设置一些文件,安装maturin
,然后展示如何构建和导入Python模块。
首先,创建一个新文件夹(让我们称它为string_sum
),其中包含以下两个文件
Cargo.toml
[lib]
name = "string_sum"
# "cdylib" is necessary to produce a shared library for Python to import from.
#
# Downstream Rust code (including code in `bin/`, `examples/`, and `tests/`) will not be able
# to `use string_sum;` unless the "rlib" or "lib" crate type is also included, e.g.:
# crate-type = ["cdylib", "rlib"]
crate-type = ["cdylib"]
[dependencies.pyo3-ffi]
version = "*"
features = ["extension-module"]
src/lib.rs
use std::os::raw::c_char;
use std::ptr;
use pyo3_ffi::*;
static mut MODULE_DEF: PyModuleDef = PyModuleDef {
m_base: PyModuleDef_HEAD_INIT,
m_name: c_str!("string_sum").as_ptr(),
m_doc: c_str!("A Python module written in Rust.").as_ptr(),
m_size: 0,
m_methods: unsafe { METHODS.as_mut_ptr().cast() },
m_slots: std::ptr::null_mut(),
m_traverse: None,
m_clear: None,
m_free: None,
};
static mut METHODS: [PyMethodDef; 2] = [
PyMethodDef {
ml_name: c_str!("sum_as_string").as_ptr(),
ml_meth: PyMethodDefPointer {
_PyCFunctionFast: sum_as_string,
},
ml_flags: METH_FASTCALL,
ml_doc: c_str!("returns the sum of two integers as a string").as_ptr(),
},
// A zeroed PyMethodDef to mark the end of the array.
PyMethodDef::zeroed()
];
// The module initialization function, which must be named `PyInit_<your_module>`.
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn PyInit_string_sum() -> *mut PyObject {
PyModule_Create(ptr::addr_of_mut!(MODULE_DEF))
}
pub unsafe extern "C" fn sum_as_string(
_self: *mut PyObject,
args: *mut *mut PyObject,
nargs: Py_ssize_t,
) -> *mut PyObject {
if nargs != 2 {
PyErr_SetString(
PyExc_TypeError,
c_str!("sum_as_string() expected 2 positional arguments").as_ptr(),
);
return std::ptr::null_mut();
}
let arg1 = *args;
if PyLong_Check(arg1) == 0 {
PyErr_SetString(
PyExc_TypeError,
c_str!("sum_as_string() expected an int for positional argument 1").as_ptr(),
);
return std::ptr::null_mut();
}
let arg1 = PyLong_AsLong(arg1);
if !PyErr_Occurred().is_null() {
return ptr::null_mut();
}
let arg2 = *args.add(1);
if PyLong_Check(arg2) == 0 {
PyErr_SetString(
PyExc_TypeError,
c_str!("sum_as_string() expected an int for positional argument 2").as_ptr(),
);
return std::ptr::null_mut();
}
let arg2 = PyLong_AsLong(arg2);
if !PyErr_Occurred().is_null() {
return ptr::null_mut();
}
match arg1.checked_add(arg2) {
Some(sum) => {
let string = sum.to_string();
PyUnicode_FromStringAndSize(string.as_ptr().cast::<c_char>(), string.len() as isize)
}
None => {
PyErr_SetString(
PyExc_OverflowError,
c_str!("arguments too large to add").as_ptr(),
);
std::ptr::null_mut()
}
}
}
在放置好这两个文件后,现在需要安装 maturin
。这可以通过使用 Python 的包管理器 pip
来完成。首先,启动一个新的 Python virtualenv
,并将 maturin
安装到其中
$ cd string_sum
$ python -m venv .env
$ source .env/bin/activate
$ pip install maturin
现在构建并执行模块
$ maturin develop
# lots of progress output as maturin runs the compilation...
$ python
>>> import string_sum
>>> string_sum.sum_as_string(5, 20)
'25'
除了使用 maturin
之外,还可以使用 setuptools-rust 或 手动 构建。两者都比 maturin
提供更多的灵活性,但需要进一步的配置。
虽然大多数项目使用 PyO3 提供的安全包装,但你也可以查看 orjson
库作为如何直接使用 pyo3-ffi
的示例。对于熟悉 C 和 Rust 的人来说,CPython 文档中的 教程 可以很容易地转换为 Rust。