๐ Foreign Function Interfaces
Foreign Function Interfaces (FFIs) in Python allow Python code to call C libraries directly. This capability is useful if you want to use legacy C code, optimise performance-critical sections of an application, or use hardware-accelerated or system-level functionality not directly available in Python. The most common tools for working with FFIs in Python are ctypes
and cffi
.
ctypes
ctypes
is a foreign function library for Python that provides C compatible data types and allows calling functions in DLLs or shared libraries. It can be used to wrap these libraries in pure Python.
Here's a simple example that uses ctypes
to call the time function from the C standard library, which returns the current time in seconds since the Epoch (1970-01-01 00:00:00 +0000 (UTC)):
import ctypes
# Load the C standard library
libc = ctypes.CDLL(None)
# Define the return type of the function we are going to call
libc.time.argtypes = [ctypes.POINTER(ctypes.c_long)]
libc.time.restype = ctypes.c_long
t = libc.time(None)
print(f"The current time is {t} seconds since the Epoch.")
cffi
cffi
(C Foreign Function Interface) is another library for calling C code from Python. Compared to ctypes
, cffi
provides more advanced features like out-of-line API mode, which allows for better error checking and integration with existing C code.
Below is an example of using cffi
to achieve the same functionality as the ctypes
example, calling the time function from the C library.
First, you need to install cffi: pip install cffi
Then, you can use cffi
like this:
from cffi import FFI
ffi = FFI()
# Define the external C function
ffi.cdef("long time(long *t);")
# Load the C standard library
C = ffi.dlopen(None)
t = ffi.new("long *")
print(f"The current time is {C.time(t)} seconds since the Epoch.")
ctypes vs cffi
ctypes
is part of the standard Python library, so it doesn't require any additional installations. It's straightforward for simple use cases but can become cumbersome for complex C libraries or where callback functions are involved.
cffi
requires installation but offers a more flexible and powerful interface for working with C code. It supports both ABI (Application Binary Interface) level and API (Application Programming Interface) level interfaces, making it suitable for more complex integration scenarios.
The choice between them ultimately depends on the specific requirements of the project, such as the complexity of the C code being interfaced and the performance requirements.
What About Fortran?
If you have legacy scientific codes, the most common way to bridge Python and Fortran is through the use of f2py
or NumPyโs integration facilities.
f2py
is one of the easiest ways to call Fortran code from Python. It generates Python wrapper modules automatically, allowing Fortran routines to be called as if they were Python functions.
Suppose you have a simple Fortran subroutine that calculates the sum of two arrays:
subroutine add_arrays(a, b, c, n)
integer, intent(in) :: n
double precision, intent(in) :: a(n), b(n)
double precision, intent(out) :: c(n)
integer :: i
do i = 1, n
c(i) = a(i) + b(i)
end do
end subroutine add_arrays
You can compile this Fortran code into a Python module using f2py
:
f2py -c -m addarrays addarrays.f90
This command creates a Python module named addarrays
. You can then import this module in Python and call the add_arrays
function:
import addarrays
import numpy as np
a = np.array([1.0, 2.0, 3.0], dtype=np.float64)
b = np.array([4.0, 5.0, 6.0], dtype=np.float64)
c = addarrays.add_arrays(a, b)
print(c)