guide: note existence of PyFunction::new_closure
This commit is contained in:
parent
86a11164e0
commit
f7537909a1
|
@ -197,12 +197,6 @@ Docstring: This function adds two unsigned 64-bit integers.
|
||||||
Type: builtin_function_or_method
|
Type: builtin_function_or_method
|
||||||
```
|
```
|
||||||
|
|
||||||
### Closures
|
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
### Calling Python functions in Rust
|
### Calling Python functions in Rust
|
||||||
|
|
||||||
You can pass Python `def`'d functions and built-in functions to Rust functions [`PyFunction`]
|
You can pass Python `def`'d functions and built-in functions to Rust functions [`PyFunction`]
|
||||||
|
@ -217,13 +211,12 @@ with only positional args.
|
||||||
|
|
||||||
### Calling Rust functions in Python
|
### Calling Rust functions in Python
|
||||||
|
|
||||||
If you have a static function, you can expose it with `#[pyfunction]` and use [`wrap_pyfunction!`]
|
The ways to convert a Rust function into a Python object vary depending on the function:
|
||||||
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`.
|
- Named functions, e.g. `fn foo()`: add `#[pyfunction]` and then use [`wrap_pyfunction!`] to get the corresponding [`PyCFunction`].
|
||||||
(A long-term solution will be a special container similar to wasm-bindgen's `Closure`). You can
|
- Anonymous functions (or closures), e.g. `foo: fn()` either:
|
||||||
then use a `#[pyclass]` struct with that container as a field as a way to pass the function over
|
- use a `#[pyclass]` struct which stores the function as a field and implement `__call__` to call the stored function.
|
||||||
the FFI barrier. You can even make that class callable with `__call__` so it looks like a function
|
- use `PyFunction::new_closure` to create an object directly from the function.
|
||||||
in Python code.
|
|
||||||
|
|
||||||
[`PyAny::is_callable`]: {{#PYO3_DOCS_URL}}/pyo3/struct.PyAny.html#tymethod.is_callable
|
[`PyAny::is_callable`]: {{#PYO3_DOCS_URL}}/pyo3/struct.PyAny.html#tymethod.is_callable
|
||||||
[`PyAny::call`]: {{#PYO3_DOCS_URL}}/pyo3/struct.PyAny.html#tymethod.call
|
[`PyAny::call`]: {{#PYO3_DOCS_URL}}/pyo3/struct.PyAny.html#tymethod.call
|
||||||
|
|
|
@ -169,14 +169,14 @@ fn parse_int(s: String) -> PyResult<usize> {
|
||||||
|
|
||||||
The Rust compiler will not permit implementation of traits for types outside of the crate where the type is defined. (This is known as the "orphan rule".)
|
The Rust compiler will not permit implementation of traits for types outside of the crate where the type is defined. (This is known as the "orphan rule".)
|
||||||
|
|
||||||
Given a type `OtherError` which is defined in thirdparty code, there are two main strategies available to integrate it with PyO3:
|
Given a type `OtherError` which is defined in third-party code, there are two main strategies available to integrate it with PyO3:
|
||||||
|
|
||||||
- Create a newtype wrapper, e.g. `MyOtherError`. Then implement `From<MyOtherError> for PyErr` (or `PyErrArguments`), as well as `From<OtherError>` for `MyOtherError`.
|
- Create a newtype wrapper, e.g. `MyOtherError`. Then implement `From<MyOtherError> for PyErr` (or `PyErrArguments`), as well as `From<OtherError>` for `MyOtherError`.
|
||||||
- Use Rust's Result combinators such as `map_err` to write code freely to convert `OtherError` into whatever is needed. This requires boilerplate at every usage however gives unlimited flexibility.
|
- Use Rust's Result combinators such as `map_err` to write code freely to convert `OtherError` into whatever is needed. This requires boilerplate at every usage however gives unlimited flexibility.
|
||||||
|
|
||||||
To detail the newtype strategy a little further, the key trick is to return `Result<T, MyOtherError>` from the `#[pyfunction]`. This means that PyO3 will make use of `From<MyOtherError> for PyErr` to create Python exceptions while the `#[pyfunction]` implementation can use `?` to convert `OtherError` to `MyOtherError` automatically.
|
To detail the newtype strategy a little further, the key trick is to return `Result<T, MyOtherError>` from the `#[pyfunction]`. This means that PyO3 will make use of `From<MyOtherError> for PyErr` to create Python exceptions while the `#[pyfunction]` implementation can use `?` to convert `OtherError` to `MyOtherError` automatically.
|
||||||
|
|
||||||
The following example demonstrates this for some imaginary thirdparty crate `some_crate` with a function `get_x` returning `Result<i32, OtherError>`:
|
The following example demonstrates this for some imaginary third-party crate `some_crate` with a function `get_x` returning `Result<i32, OtherError>`:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# mod some_crate {
|
# mod some_crate {
|
||||||
|
|
Loading…
Reference in New Issue