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-03 11:39:07 +00:00
m.add_function(wrap_pyfunction!(double)).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-03 11:39:07 +00:00
m.add_function(wrap_pyfunction!(num_kwds)).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
}
}
```
### 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
2019-04-17 09:35:29 +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-05-03 12:12:51 +00:00
You can 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-03-18 15:26:34 +00:00
If you have a static function, you can expose it with `#[pyfunction]` and use [`wrap_pyfunction!`] to get the corresponding [`PyObject`]. 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-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-04 08:02:40 +00:00
fn pyfunction_with_module(
module: & PyModule
) -> PyResult< & str> {
module.name()
}
#[pymodule]
fn module_with_fn(py: Python, m: & PyModule) -> PyResult< ()> {
m.add_function(wrap_pyfunction!(pyfunction_with_module))
}
# 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() {}
```