Best Python bindings crate?

I'm working on a GUI-based application. It's written in Python and uses numpy for handing images around and doing processing on them.

I have some Rust code that uses ndarray, that I'd like to use for processing under the hood. I'm only interested in calling Rust code from Python -- not the other way around.

Typically, I expect to be calling Rust functions from Python code with arguments that may contain arrays, and getting responses that may themselves contain arrays. It would be nice if the translation from numpy array to ndarray and back were seamless.

Is there a "best" crate for this? Searches come up with pyO3 and cpython -- is there a clear winner between these for my purposes, or a third contender that I haven't encountered?

As far as I can tell from posts on this forum, PyO3 is much more widely used than cpython. The stats at bear this out [1, 2]. Both libraries are maintained, but PyO3 has had more frequent releases than cpython recently; the last release of cpython was 5 months ago.

You might be able to use the numpy crate—part of the PyO3 ecosystem—to hook up numpy to ndarray, but I'm not sure about that. It seems to be focused on the "calling Python from Rust" use-case.

Here is a page from the PyO3 documentation that contrasts it with cpython.


I've used pyo3 in the past and it's done pretty well for what I need.

I wouldn't worry too much about finding the "best" crate. Just find something that works (both pyo3 and cpython as re quite capable) then structure your code so the Python-Rust interface is as thin and simple as possible (e.g. translate arguments then call a function from the main Rust crate) and you should be fine.


I'm definitely really only interested in the "call Rust from Python" use case, unless for some reason I need callbacks.