Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

在 Rust 程式碼中呼叫 Python

本章說明從 Rust 與 Python 程式碼互動的幾種方式。

以下將介紹 'py 生命週期,以及 PyO3 API 如何思考 Python 程式碼的一些一般說明。

子章節也涵蓋以下主題:

  • PyO3 API 中可用的 Python 物件型別
  • 如何處理 Python 例外狀況
  • 如何呼叫 Python 函式
  • 如何執行既有的 Python 程式碼

'py 生命週期

要安全地與 Python 直譯器互動,Rust 執行緒必須附著於 Python 直譯器。PyO3 提供 Python<'py> token 用來證明已滿足這些條件,其生命週期 'py 是 PyO3 API 的核心部分。

Python<'py> token 有三個用途:

  • 它提供 Python 直譯器的全域 API,例如 py.eval()py.import()
  • 它可傳遞給需要附著證明的函式,例如 Py::clone_ref
  • 其生命週期 'py 用來將多種 PyO3 型別綁定到 Python 直譯器,例如 Bound<'py, T>

綁定 'py 生命週期的 PyO3 型別(例如 Bound<'py, T>)都包含 Python<'py> token。這表示它們能完整存取 Python 直譯器,並提供與 Python 物件互動的完整 API。

請參考 PyO3 API 文件 了解如何取得此 token。

全域直譯器鎖(GIL)

Prior to the introduction of free-threaded Python (first available in 3.13, fully supported in 3.14), the Python interpreter was made thread-safe by the global interpreter lock. This ensured that only one Python thread can use the Python interpreter and its API at the same time. Historically, Rust code was able to use the GIL as a synchronization guarantee, but the introduction of free-threaded Python removed this possibility.

pyo3::sync 模組提供同步工具,可抽象化兩種 Python 版本的差異。

為了在有 GIL 的版本中啟用並行、以及在自由執行緒版本中獲得最佳吞吐量,非 Python 的操作(系統呼叫與原生 Rust 程式碼)應考慮暫時與直譯器分離,以便其他工作繼續進行。如何使用 PyO3 API 進行分離,請見並行章節

Python 的記憶體模型

Python’s memory model differs from Rust’s memory model in two key ways:

  • There is no concept of ownership; all Python objects are shared and usually implemented via reference counting
  • There is no concept of exclusive (&mut) references; any reference can mutate a Python object

PyO3’s API reflects this by providing smart pointer types, Py<T>, Bound<'py, T>, and (the very rarely used) Borrowed<'a, 'py, T>. These smart pointers all use Python reference counting. See the subchapter on types for more detail on these types.

Because of the lack of exclusive &mut references, PyO3’s APIs for Python objects, for example PyListMethods::append, use shared references. This is safe because Python objects have internal mechanisms to prevent data races (as of time of writing, the Python GIL).