2019-04-17 09:35:29 +00:00
|
|
|
# Python Functions
|
2017-06-18 02:02:02 +00:00
|
|
|
|
2019-04-17 09:35:29 +00:00
|
|
|
PyO3 supports two ways to define a free function in Python. Both require registering
|
|
|
|
the function to a [module](./module.md).
|
2018-04-30 21:17:09 +00:00
|
|
|
|
2020-03-13 13:53:49 +00:00
|
|
|
One way is defining the function in the module definition, annotated with `#[pyfn]`.
|
2018-04-30 21:17:09 +00:00
|
|
|
|
|
|
|
```rust
|
2018-07-08 21:33:48 +00:00
|
|
|
use pyo3::prelude::*;
|
2018-07-18 11:08:05 +00:00
|
|
|
|
2018-11-12 21:28:45 +00:00
|
|
|
#[pymodule]
|
2018-07-09 22:13:02 +00:00
|
|
|
fn rust2py(py: Python, m: &PyModule) -> PyResult<()> {
|
2018-04-30 21:17:09 +00:00
|
|
|
|
|
|
|
#[pyfn(m, "sum_as_string")]
|
2018-05-05 13:50:04 +00:00
|
|
|
fn sum_as_string_py(_py: Python, a:i64, b:i64) -> PyResult<String> {
|
2020-03-13 13:53:49 +00:00
|
|
|
Ok(format!("{}", a + b))
|
2018-04-30 21:17:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
# fn main() {}
|
|
|
|
```
|
|
|
|
|
2018-12-07 14:22:12 +00:00
|
|
|
The other is annotating a function with `#[pyfunction]` and then adding it
|
2019-04-17 09:35:29 +00:00
|
|
|
to the module using the `wrap_pyfunction!` macro.
|
2018-04-30 21:17:09 +00:00
|
|
|
|
|
|
|
```rust
|
2018-07-08 21:33:48 +00:00
|
|
|
use pyo3::prelude::*;
|
2019-02-01 13:01:18 +00:00
|
|
|
use pyo3::wrap_pyfunction;
|
2018-04-30 21:17:09 +00:00
|
|
|
|
2018-05-05 13:50:04 +00:00
|
|
|
#[pyfunction]
|
2018-04-30 21:17:09 +00:00
|
|
|
fn double(x: usize) -> usize {
|
|
|
|
x * 2
|
|
|
|
}
|
|
|
|
|
2018-11-12 21:28:45 +00:00
|
|
|
#[pymodule]
|
2018-07-09 22:13:02 +00:00
|
|
|
fn module_with_functions(py: Python, m: &PyModule) -> PyResult<()> {
|
2020-09-09 09:53:24 +00:00
|
|
|
m.add_function(wrap_pyfunction!(double, m)?).unwrap();
|
2018-04-30 21:17:09 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
# fn main() {}
|
|
|
|
```
|
2018-08-04 17:55:15 +00:00
|
|
|
|
2019-04-18 05:59:15 +00:00
|
|
|
## Argument parsing
|
|
|
|
|
|
|
|
Both the `#[pyfunction]` and `#[pyfn]` attributes support specifying details of
|
|
|
|
argument parsing. The details are given in the section "Method arguments" in
|
|
|
|
the [Classes](class.md) chapter. Here is an example for a function that accepts
|
|
|
|
arbitrary keyword arguments (`**kwargs` in Python syntax) and returns the number
|
|
|
|
that was passed:
|
|
|
|
|
|
|
|
```rust
|
|
|
|
# extern crate pyo3;
|
|
|
|
use pyo3::prelude::*;
|
|
|
|
use pyo3::wrap_pyfunction;
|
|
|
|
use pyo3::types::PyDict;
|
|
|
|
|
|
|
|
#[pyfunction(kwds="**")]
|
|
|
|
fn num_kwds(kwds: Option<&PyDict>) -> usize {
|
|
|
|
kwds.map_or(0, |dict| dict.len())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[pymodule]
|
|
|
|
fn module_with_functions(py: Python, m: &PyModule) -> PyResult<()> {
|
2020-09-09 09:53:24 +00:00
|
|
|
m.add_function(wrap_pyfunction!(num_kwds, m)?).unwrap();
|
2019-04-18 05:59:15 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
# fn main() {}
|
|
|
|
```
|
|
|
|
|
2019-11-29 21:22:31 +00:00
|
|
|
## Making the function signature available to Python
|
2018-12-07 14:22:40 +00:00
|
|
|
|
|
|
|
In order to make the function signature available to Python to be retrieved via
|
2019-11-29 21:22:31 +00:00
|
|
|
`inspect.signature`, use the `#[text_signature]` annotation as in the example
|
2020-03-13 13:53:49 +00:00
|
|
|
below. The `/` signifies the end of positional-only arguments. (This
|
|
|
|
is not a feature of this library in particular, but the general format used by
|
|
|
|
CPython for annotating signatures of built-in functions.)
|
2019-11-29 21:22:31 +00:00
|
|
|
|
|
|
|
```rust
|
|
|
|
use pyo3::prelude::*;
|
|
|
|
|
|
|
|
/// This function adds two unsigned 64-bit integers.
|
|
|
|
#[pyfunction]
|
|
|
|
#[text_signature = "(a, b, /)"]
|
|
|
|
fn add(a: u64, b: u64) -> u64 {
|
|
|
|
a + b
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
This also works for classes and methods:
|
|
|
|
|
|
|
|
```rust
|
|
|
|
use pyo3::prelude::*;
|
|
|
|
use pyo3::types::PyType;
|
|
|
|
|
|
|
|
// it works even if the item is not documented:
|
|
|
|
|
|
|
|
#[pyclass]
|
|
|
|
#[text_signature = "(c, d, /)"]
|
|
|
|
struct MyClass {}
|
|
|
|
|
|
|
|
#[pymethods]
|
|
|
|
impl MyClass {
|
|
|
|
// the signature for the constructor is attached
|
|
|
|
// to the struct definition instead.
|
|
|
|
#[new]
|
2019-12-22 10:41:25 +00:00
|
|
|
fn new(c: i32, d: &str) -> Self {
|
|
|
|
Self {}
|
2019-11-29 21:22:31 +00:00
|
|
|
}
|
|
|
|
// the self argument should be written $self
|
|
|
|
#[text_signature = "($self, e, f)"]
|
|
|
|
fn my_method(&self, e: i32, f: i32) -> i32 {
|
|
|
|
e + f
|
|
|
|
}
|
|
|
|
#[classmethod]
|
|
|
|
#[text_signature = "(cls, e, f)"]
|
|
|
|
fn my_class_method(cls: &PyType, e: i32, f: i32) -> i32 {
|
|
|
|
e + f
|
|
|
|
}
|
|
|
|
#[staticmethod]
|
|
|
|
#[text_signature = "(e, f)"]
|
|
|
|
fn my_static_method(e: i32, f: i32) -> i32 {
|
|
|
|
e + f
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2020-12-13 15:26:37 +00:00
|
|
|
Note that `text_signature` on classes is not compatible with compilation in
|
|
|
|
`abi3` mode until Python 3.10 or greater.
|
|
|
|
|
2019-11-29 21:22:31 +00:00
|
|
|
### Making the function signature available to Python (old method)
|
|
|
|
|
|
|
|
Alternatively, simply make sure the first line of your docstring is
|
|
|
|
formatted like in the following example. Please note that the newline after the
|
2020-03-13 13:53:49 +00:00
|
|
|
`--` is mandatory. The `/` signifies the end of positional-only arguments.
|
2018-12-07 14:22:40 +00:00
|
|
|
|
2019-11-29 21:22:31 +00:00
|
|
|
`#[text_signature]` should be preferred, since it will override automatically
|
|
|
|
generated signatures when those are added in a future version of PyO3.
|
|
|
|
|
2018-12-07 14:22:40 +00:00
|
|
|
```rust
|
2019-02-14 09:41:52 +00:00
|
|
|
use pyo3::prelude::*;
|
|
|
|
|
2018-12-07 14:22:40 +00:00
|
|
|
/// add(a, b, /)
|
|
|
|
/// --
|
|
|
|
///
|
|
|
|
/// This function adds two unsigned 64-bit integers.
|
|
|
|
#[pyfunction]
|
|
|
|
fn add(a: u64, b: u64) -> u64 {
|
|
|
|
a + b
|
|
|
|
}
|
2019-11-29 21:22:31 +00:00
|
|
|
|
|
|
|
// a function with a signature but without docs. Both blank lines after the `--` are mandatory.
|
|
|
|
|
|
|
|
/// sub(a, b, /)
|
|
|
|
/// --
|
|
|
|
///
|
|
|
|
///
|
|
|
|
#[pyfunction]
|
|
|
|
fn sub(a: u64, b: u64) -> u64 {
|
|
|
|
a - b
|
|
|
|
}
|
2018-12-07 14:22:40 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
When annotated like this, signatures are also correctly displayed in IPython.
|
2020-03-13 13:53:49 +00:00
|
|
|
|
2019-02-14 09:41:52 +00:00
|
|
|
```ignore
|
2018-12-07 14:22:40 +00:00
|
|
|
>>> pyo3_test.add?
|
|
|
|
Signature: pyo3_test.add(a, b, /)
|
|
|
|
Docstring: This function adds two unsigned 64-bit integers.
|
|
|
|
Type: builtin_function_or_method
|
|
|
|
```
|
|
|
|
|
2018-08-04 17:55:15 +00:00
|
|
|
## Closures
|
|
|
|
|
2020-09-11 11:22:36 +00:00
|
|
|
Currently, there are no conversions between `Fn`s in Rust and callables in Python. This would
|
|
|
|
definitely be possible and very useful, so contributions are welcome. In the meantime, you can do
|
|
|
|
the following:
|
2018-08-04 17:55:15 +00:00
|
|
|
|
2020-03-13 13:53:49 +00:00
|
|
|
### Calling Python functions in Rust
|
2018-08-04 17:55:15 +00:00
|
|
|
|
2020-09-11 11:22:36 +00:00
|
|
|
You can pass Python `def`'d functions and built-in functions to Rust functions `[PyFunction]`
|
|
|
|
corresponds to regular Python functions while `[PyCFunction]` describes built-ins such as
|
|
|
|
`repr()`.
|
|
|
|
|
|
|
|
You can also use [`PyAny::is_callable`] to check if you have a callable object. `is_callable` will
|
|
|
|
return `true` for functions (including lambdas), methods and objects with a `__call__` method.
|
|
|
|
You can call the object with [`PyAny::call`] with the args as first parameter and the kwargs
|
|
|
|
(or `None`) as second parameter. There are also [`PyAny::call0`] with no args and [`PyAny::call1`]
|
|
|
|
with only positional args.
|
2018-08-04 17:55:15 +00:00
|
|
|
|
2020-03-13 13:53:49 +00:00
|
|
|
### Calling Rust functions in Python
|
2018-08-04 17:55:15 +00:00
|
|
|
|
2020-09-11 11:22:36 +00:00
|
|
|
If you have a static function, you can expose it with `#[pyfunction]` and use [`wrap_pyfunction!`]
|
|
|
|
to get the corresponding [`PyCFunction`]. For dynamic functions, e.g. lambdas and functions that
|
|
|
|
were passed as arguments, you must put them in some kind of owned container, e.g. a `Box`.
|
|
|
|
(A long-term solution will be a special container similar to wasm-bindgen's `Closure`). You can
|
|
|
|
then use a `#[pyclass]` struct with that container as a field as a way to pass the function over
|
|
|
|
the FFI barrier. You can even make that class callable with `__call__` so it looks like a function
|
|
|
|
in Python code.
|
2020-03-18 15:26:34 +00:00
|
|
|
|
2020-05-03 12:12:51 +00:00
|
|
|
[`PyAny::is_callable`]: https://docs.rs/pyo3/latest/pyo3/struct.PyAny.html#tymethod.is_callable
|
|
|
|
[`PyAny::call`]: https://docs.rs/pyo3/latest/pyo3/struct.PyAny.html#tymethod.call
|
|
|
|
[`PyAny::call0`]: https://docs.rs/pyo3/latest/pyo3/struct.PyAny.html#tymethod.call0
|
|
|
|
[`PyAny::call1`]: https://docs.rs/pyo3/latest/pyo3/struct.PyAny.html#tymethod.call1
|
2020-08-06 21:29:05 +00:00
|
|
|
[`PyObject`]: https://docs.rs/pyo3/latest/pyo3/type.PyObject.html
|
2020-03-18 15:26:34 +00:00
|
|
|
[`wrap_pyfunction!`]: https://docs.rs/pyo3/latest/pyo3/macro.wrap_pyfunction.html
|
2020-09-04 08:02:40 +00:00
|
|
|
|
|
|
|
### Accessing the module of a function
|
|
|
|
|
2020-09-05 08:06:24 +00:00
|
|
|
It is possible to access the module of a `#[pyfunction]` and `#[pyfn]` in the
|
|
|
|
function body by passing the `pass_module` argument to the attribute:
|
2020-09-04 08:02:40 +00:00
|
|
|
|
|
|
|
```rust
|
|
|
|
use pyo3::wrap_pyfunction;
|
|
|
|
use pyo3::prelude::*;
|
|
|
|
|
2020-09-05 08:06:24 +00:00
|
|
|
#[pyfunction(pass_module)]
|
2020-09-05 09:22:13 +00:00
|
|
|
fn pyfunction_with_module(module: &PyModule) -> PyResult<&str> {
|
2020-09-04 08:02:40 +00:00
|
|
|
module.name()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[pymodule]
|
|
|
|
fn module_with_fn(py: Python, m: &PyModule) -> PyResult<()> {
|
2020-09-09 09:53:24 +00:00
|
|
|
m.add_function(wrap_pyfunction!(pyfunction_with_module, m)?)
|
2020-09-04 08:02:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# fn main() {}
|
|
|
|
```
|
|
|
|
|
2020-09-05 08:06:24 +00:00
|
|
|
If `pass_module` is set, the first argument **must** be the `&PyModule`. It is then possible to use the module
|
|
|
|
in the function body.
|
2020-09-04 08:02:40 +00:00
|
|
|
|
|
|
|
The same works for `#[pyfn]`:
|
|
|
|
|
|
|
|
```rust
|
|
|
|
use pyo3::wrap_pyfunction;
|
|
|
|
use pyo3::prelude::*;
|
|
|
|
|
|
|
|
#[pymodule]
|
|
|
|
fn module_with_fn(py: Python, m: &PyModule) -> PyResult<()> {
|
|
|
|
|
2020-09-05 08:06:24 +00:00
|
|
|
#[pyfn(m, "module_name", pass_module)]
|
2020-09-04 08:02:40 +00:00
|
|
|
fn module_name(module: &PyModule) -> PyResult<&str> {
|
|
|
|
module.name()
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
# fn main() {}
|
|
|
|
```
|
2020-09-11 11:22:36 +00:00
|
|
|
|
|
|
|
## Accessing the FFI functions
|
|
|
|
|
|
|
|
In order to make Rust functions callable from Python, PyO3 generates a
|
|
|
|
`extern "C" Fn(slf: *mut PyObject, args: *mut PyObject, kwargs: *mut PyObject) -> *mut Pyobject`
|
|
|
|
function and embeds the call to the Rust function inside this FFI-wrapper function. This
|
|
|
|
wrapper handles extraction of the regular arguments and the keyword arguments from the input
|
|
|
|
`PyObjects`. Since this function is not user-defined but required to build a `PyCFunction`, PyO3
|
|
|
|
offers the `raw_pycfunction!()` macro to get the identifier of this generated wrapper.
|
|
|
|
|
|
|
|
The `wrap_pyfunction` macro can be used to directly get a `PyCFunction` given a
|
|
|
|
`#[pyfunction]` and a `PyModule`: `wrap_pyfunction!(rust_fun, module)`.
|