📑
PyO3が生成するコードを眺めてみる
2021/03/09 追記
ここにほとんど書いてあるっぽい
検証環境
- Linux 5.4.0-66-generic #74~18.04.2-Ubuntu SMP Fri Feb 5 11:17:31 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
- ZorinOS core版 15.3
- Docker version 20.10.5, build 55c4c88
- docker-compose version 1.27.4, build 40524192
- rust:1.50-slim-buster
- rustc 1.50.0 (cb75ad5db 2021-02-10)
- cargo 1.50.0 (f04e7fab7 2021-02-04)
リポジトリ
Cargo.toml
[package]
name = "pyo3_test"
version = "0.1.0"
authors = ["booink <booink.work@gmail.com>"]
edition = "2018"
[lib]
name = "pyo3_test"
crate-type = ["cdylib"]
[dependencies]
pyo3 = { version = "0.13.1", extension-module = ["extension-module"], default = ["extension-module"] }
src/lib.rs
PyO3 で構造体を外出しするだけの単純なコードに留めておきます。
use pyo3::prelude::*;
#[pyclass]
struct Hello {
#[pyo3(get)]
world: String,
}
#[pymodule]
fn pyo3_test(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<Hello>()?;
Ok(())
}
cargo expand
nightly 版じゃないと error: the option
Z is only accepted on the nightly compiler
と怒られるので、nightly 版を使えるようにしてから expand コマンドを実行します。
rustup toolchain install nightly
cargo expand > expand/pyo3_test.rs
expandしたコード
(吐き出したままのソースだと若干見づらかったので、インデントを変更してます)
line 1 - 5
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::v1::*;
#[macro_use]
extern crate std;
標準ライブラリの呼び出し。
空っぽの src/lib.rs に対して cargo expand すると、↑これだけが出力される。
line 6 - 10
use pyo3::prelude::*;
struct Hello {
world: String,
}
定義した構造体がそのまま出力されている。
line 11 - 28
unsafe impl pyo3::type_object::PyTypeInfo for Hello {
type Type = Hello;
type BaseType = pyo3::PyAny;
type Layout = pyo3::PyCell<Self>;
type BaseLayout = pyo3::pycell::PyCellBase<pyo3::PyAny>;
type Initializer = pyo3::pyclass_init::PyClassInitializer<Self>;
type AsRefTarget = pyo3::PyCell<Self>;
const NAME: &'static str = "Hello";
const MODULE: Option<&'static str> = None;
const DESCRIPTION: &'static str = "\u{0}";
const FLAGS: usize = 0 | 0;
#[inline]
fn type_object_raw(py: pyo3::Python) -> *mut pyo3::ffi::PyTypeObject {
use pyo3::type_object::LazyStaticType;
static TYPE_OBJECT: LazyStaticType = LazyStaticType::new();
TYPE_OBJECT.get_or_init::<Self>(py)
}
}
PyTypeInfo
traitの実装。
FFIでPythonから使えるようにするための型情報だろうか。
line 29 - 33
impl pyo3::PyClass for Hello {
type Dict = pyo3::pyclass_slots::PyClassDummySlot;
type WeakRef = pyo3::pyclass_slots::PyClassDummySlot;
type BaseNativeType = pyo3::PyAny;
}
PyClass
traitの実装。
If
PyClass
is implemented forT
, then we can useT
in the Python world, viaPyCell
.
PyCell
を経由して Python 側に任意の構造体を使えるようにしている、的なこと。
PyClassDummySlot
型が気になるが、後回し。
line 34 - 47
impl <'a> pyo3::derive_utils::ExtractExt<'a> for &'a Hello {
type Target = pyo3::PyRef<'a, Hello>;
}
impl <'a> pyo3::derive_utils::ExtractExt<'a> for &'a mut Hello {
type Target = pyo3::PyRefMut<'a, Hello>;
}
impl pyo3::pyclass::PyClassSend for Hello {
type ThreadChecker = pyo3::pyclass::ThreadCheckerStub<Hello>;
}
impl pyo3::IntoPy<pyo3::PyObject> for Hello {
fn into_py(self, py: pyo3::Python) -> pyo3::PyObject {
pyo3::IntoPy::into_py(pyo3::Py::new(py, self).unwrap(), py)
}
}
ExtractExt
Utility trait to enable &PyClass as a pymethod/function argument
#[pyclass]
で定義した構造体の実装で pymethods などを使えるようにするためのユーティリティトレイト、みたいな感じ?
PyClassSend
眠い。今日はここまで。
後日追記します。
Discussion