Calling Rust code from Python is a powerful way to combine the performance and safety of Rust with the simplicity and ease of use of Python. In this post, we will explore how to call Rust code from Python, and discuss the benefits of using these two languages together.
Table of contents
Open Table of contents
Installing Rust and Creating a New Project
The first step in calling Rust code from Python is to install Rust on your computer. You can do this by following the instructions on the Rust website rust-lang. Once Rust is installed, you can create a new Rust project by running the following command:
cargo new rust-python-project
This will create a new directory named rust-python-project
with the necessary files and directories for a Rust project.
Compiling the Rust Code
Next, we need to compile our Rust code into a shared library that can be called from Python. To do this, open the Cargo.toml file in your favorite text editor, and add the following lines to it:
[lib]
name = "rust_python_project"
crate-type = ["cdylib"]
This tells the Rust compiler that we want to create a shared library named rust_python_project
, and that it should be compiled as a C-style dynamic library.
Next, create a file named src/lib.rs
and add the following Rust code to it:
#[no_mangle]
pub extern fn add_one(x: u32) -> u32 {
x + 1
}
This is a simple Rust function that takes a 32-bit unsigned integer as input, and returns the result of adding one to that number. We will use this function to demonstrate how to call Rust code from Python.
To compile the Rust code, run the following command:
cargo build --release
This will create a shared library named rust_python_project
in the target/release
directory. This is the library that we will call from Python.
Calling Rust Code from Python
To call the Rust code from Python, we need to use a Foreign Function Interface (FFI) library. There are several options available, but in this post we will use the cffi library. To install cffi
, run the following command:
pip install cffi
Once cffi
is installed, you can call the Rust code from Python using the following steps:
- Import the cffi library in your Python code:
import cffi
- Define the Rust functions and data structures that you want to call using the
ffi.cdef
statement:
ffi = cffi.FFI()
ffi.cdef("""uint32_t add_one(uint32_t x);""")
In this example, we are defining the add_one
function from our Rust code. This tells the cffi
library that we want to call a Rust function named add_one
that takes a 32-bit unsigned integer as input, and returns a 32-bit unsigned integer as output.
- Use the
ffi.dlopen
function to load the compiled Rust library:
# Replace /path/to/rust/release with the actual path to the compiled Rust library
lib = ffi.dlopen("/path/to/rust/release/librust_python_project.dylib")
This will load the rust_python_project
library that we created earlier using the Rust compiler.
- Call the Rust functions and data structures using the
lib
object:
# Call the add_one function from Rust
result = lib.add_one(10)
print(result) # This should print 11
This code calls the add_one
function from our Rust code, passing the number 10 as the input argument. The function returns the result of adding one to that number, so the code should print the number 11 to the screen.
That’s it! You have successfully called Rust code from Python using the cffi
library.
Benefits of Calling Rust Code from Python
There are several benefits to calling Rust code from Python:
-
Improved performance: Rust is a statically-typed, compiled language that is known for its performance and memory safety. By using Rust for performance-critical parts of your code, such as data parsing or numerical calculations, you can significantly improve the performance of your Python applications.
-
Increased safety and reliability: Since Rust is statically-typed, it can catch many types of bugs at compile time, before your code is even run. This can save you a lot of time and effort, and can help prevent bugs and other issues from creeping into your code.
-
Maintainability: By separating your code into performance-critical Rust functions and the rest of your Python code, you can create applications that are easier to maintain and modify. This can make your code more flexible and adaptable, and can help you respond to changing requirements and other challenges.
Overall, calling Rust code from Python can be a powerful way to combine the best of both worlds. By using Rust for performance-critical parts of your code, and Python for the rest, you can create high-performance, reliable, and maintainable applications.
Notes
#[no_mangle]
The #[no_mangle]
attribute is applied to the add_one
function. This attribute tells the Rust compiler not to “mangle” the name of the function when it is compiled.
Mangling is the process of modifying the name of a function or other symbol to make it unique. This is often done to avoid conflicts with other symbols in the code, or to encode information about the symbol in its name. By default, the Rust compiler mangles the names of functions and other symbols to ensure that they are unique and do not cause conflicts.
However, in this case, we want to call the add_one
function from Python. In order to do this, the name of the function must remain the same, so that Python knows which function to call. By applying the #[no_mangle]
attribute to the add_one
function, we are telling the Rust compiler not to mangle the name of the function, and to keep it the same as it is in the Rust code. This allows us to call the add_one function from Python without any issues.