安裝
要開始使用 PyO3,你需要三樣東西:Rust 工具鏈、Python 環境,以及建置方式。下面將逐一說明。
[!TIP] 如果你想與 PyO3 維護者和其他 PyO3 使用者聊天,請考慮加入 PyO3 Discord 伺服器。我們很想聽聽你開始使用時的體驗,讓 PyO3 對每個人都更容易上手!
Rust
First, make sure you have Rust installed on your system. If you haven’t already done so, try following the instructions on the Rust website. PyO3 runs on both the stable and nightly versions so you can choose whichever one fits you best. The minimum required Rust version is 1.83.
如果你能執行 rustc --version 並且版本足夠新,就可以開始了!
Python
要使用 PyO3,至少需要 Python 3.7。雖然可直接使用系統預設的 Python 直譯器,但建議使用虛擬環境。
虛擬環境
While you can use any virtualenv manager you like, we recommend the use of pyenv in particular if you want to develop or test for multiple different Python versions, so that is what the examples in this book will use. The installation instructions for pyenv can be found in the pyenv GitHub repository. (Note: To get the pyenv activate and pyenv virtualenv commands, you will also need to install the pyenv-virtualenv plugin. The pyenv installer will install both together.)
使用 pyenv 安裝時保留來源檔可能對日後除錯有幫助,可在 pyenv install 命令中加入 --keep 旗標。
例如:
pyenv install 3.12 --keep
建置
There are a number of build and Python package management systems such as setuptools-rust or manually. We recommend the use of maturin, which you can install as per the maturin documentation. It is developed to work with PyO3 and provides the most “batteries included” experience, especially if you are aiming to publish to PyPI. maturin is just a Python package, so you can add it in the same way you already install Python packages.
系統 Python:
pip install maturin --user
pipx:
pipx install maturin
pyenv:
pyenv activate pyo3
pip install maturin
poetry:
poetry add -G dev maturin
安裝完成後,可執行 maturin --version 以確認是否安裝成功。
開始新專案
首先建立要放置新專案的資料夾與虛擬環境。此處將使用推薦的 pyenv:
mkdir pyo3-example
cd pyo3-example
pyenv virtualenv pyo3
pyenv local pyo3
接著安裝建置工具。這個例子使用 maturin。啟用 virtualenv 後,將 maturin 安裝進去:
pip install maturin
現在可以初始化新專案:
maturin init
如果已安裝 maturin,也可直接用它建立新專案:
maturin new -b pyo3 pyo3-example
cd pyo3-example
pyenv virtualenv pyo3
pyenv local pyo3
加入既有專案
可惜目前 maturin 無法在既有專案中執行,因此若要在既有專案中使用 Python,基本上有兩個選擇:
- 如上建立新專案並將既有程式碼移入
- 依需求手動編輯專案設定
若選擇第二種作法,請注意以下事項:
Cargo.toml
請確保你要讓 Python 存取的 Rust 軟體箱是以函式庫形式編譯。你也可以同時輸出二進位檔,但要讓 Python 存取的程式碼必須在函式庫部分。此外,請確保軟體箱型別為 cdylib,並依下列方式加入 PyO3 相依性:
# If you already have [package] information in `Cargo.toml`, you can ignore
# this section!
[package]
# `name` here is name of the package.
name = "pyo3_start"
# these are good defaults:
version = "0.1.0"
edition = "2021"
[lib]
# The name of the native library. This is the name which will be used in Python to import the
# library (i.e. `import string_sum`). If you change this, you must also change the name of the
# `#[pymodule]` in `src/lib.rs`.
name = "pyo3_example"
# "cdylib" is necessary to produce a shared library for Python to import from.
crate-type = ["cdylib"]
[dependencies]
pyo3 = git = "https://github.com/pyo3/pyo3"
pyproject.toml
你也應建立一個 pyproject.toml,內容如下:
[build-system]
requires = ["maturin>=1.9.4,<2"]
build-backend = "maturin"
[project]
name = "pyo3_example"
requires-python = ">=3.7"
classifiers = [
"Programming Language :: Rust",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
]
執行程式碼
接著可依下列方式設定讓 Python 可使用 Rust 程式碼;例如將程式碼放在 src/lib.rs:
/// 以 Rust 實作的 Python 模組。此函式名稱必須
/// 與 `Cargo.toml` 中的 `lib.name` 設定一致,
/// 否則 Python 將無法匯入該模組。
#[pyo3::pymodule]
mod pyo3_example {
use pyo3::prelude::*;
/// 將兩個數字的總和格式化為字串。
#[pyfunction]
fn sum_as_string(a: usize, b: usize) -> PyResult<String> {
Ok((a + b).to_string())
}
}
現在可以執行 maturin develop 準備 Python 軟體包,之後可如下使用:
$ maturin develop
# maturin 執行編譯時會輸出大量進度訊息...
$ python
>>> import pyo3_example
>>> pyo3_example.sum_as_string(5, 20)
'25'
更多關於如何從 Rust 使用 Python 程式碼的說明,請見 Python from Rust。
Maturin 匯入掛鉤
In development, any changes in the code would require running maturin develop before testing. To streamline the development process, you may want to install Maturin Import Hook which will run maturin develop automatically when the library with code changes is being imported.