Type Conversions
PyO3 provides some handy traits to convert between Python types and Rust types.
.extract()
The easiest way to convert a Python object to a Rust value is using .extract()?
.
ToPyObject
trait
ToPyObject
trait is a conversion trait that allows various objects to be
converted into PyObject
. IntoPy<PyObject>
serves the
same purpose, except that it consumes self
.
FromPyObject
and RefFromPyObject
trait
*args
and **kwargs
for python object call
There are several ways how to pass positional and keyword arguments to a Python object call.
The ObjectProtocol
trait provides two methods:
call
- call any callable Python object.call_method
- call a specific method on the object, shorthand forget_attr
thencall
.
Both methods accept args
and kwargs
arguments.
use pyo3::prelude::*;
use pyo3::types::{PyDict, PyTuple};
struct SomeObject;
impl SomeObject {
fn new(py: Python) -> PyObject {
PyDict::new(py).to_object(py)
}
}
fn main() {
let arg1 = "arg1";
let arg2 = "arg2";
let arg3 = "arg3";
let gil = Python::acquire_gil();
let py = gil.python();
let obj = SomeObject::new(py);
// call object without empty arguments
obj.call0(py);
// call object with PyTuple
let args = PyTuple::new(py, &[arg1, arg2, arg3]);
obj.call1(py, args);
// pass arguments as rust tuple
let args = (arg1, arg2, arg3);
obj.call1(py, args);
}
kwargs
can be None
or Some(&PyDict)
. You can use the
IntoPyDict
trait to convert other dict-like containers, e.g. HashMap
, BTreeMap
as well as tuples with up to 10 elements and Vec
s where each element is a two-element tuple.
use pyo3::prelude::*;
use pyo3::types::{IntoPyDict, PyDict};
use std::collections::HashMap;
struct SomeObject;
impl SomeObject {
fn new(py: Python) -> PyObject {
PyDict::new(py).to_object(py)
}
}
fn main() {
let key1 = "key1";
let val1 = 1;
let key2 = "key2";
let val2 = 2;
let gil = Python::acquire_gil();
let py = gil.python();
let obj = SomeObject::new(py);
// call object with PyDict
let kwargs = [(key1, val1)].into_py_dict(py);
obj.call(py, (), Some(kwargs));
// pass arguments as Vec
let kwargs = vec![(key1, val1), (key2, val2)];
obj.call(py, (), Some(kwargs.into_py_dict(py)));
// pass arguments as HashMap
let mut kwargs = HashMap::<&str, i32>::new();
kwargs.insert(key1, 1);
obj.call(py, (), Some(kwargs.into_py_dict(py)));
}
IntoPy<T>
Many conversions in PyO3 can't use std::convert::Into
because they need a GIL token. That's why the IntoPy<T>
trait offers an into_py
method that works just like into
, except for taking a Python<'_>
argument.
Eventually, traits such as ToPyObject
will be replaced by this trait and a FromPy
trait will be added that will implement IntoPy
, just like with From
and Into
.