Python adalah bahasa tingkat tinggi yang hebat untuk prototyping dan analisis data, tetapi eksekusinya jauh lebih lambat dari C untuk loop numerik berat. Kabar baiknya: Python dapat memanggil kode C langsung lewat beberapa mekanisme FFI: ctypes (built-in, memuat .so langsung), cffi (mirip ctypes tetapi lebih ergonomis), dan CPython extension (modul native yang ditulis dengan Python C API). Mekanisme yang paling sederhana dan paling portabel adalah ctypes—kita akan fokus pada ini. Pada chapter ini kita akan membangun libmatema.so lalu memanggilnya dari Python dengan ctypes.
Membangun Library C untuk Python #
Library yang dipanggil dari Python tidak ada bedanya dengan library C biasa—kita build dengan -fPIC -shared. Kuncinya: header harus memakai extern "C" agar nama symbol tidak ter-mangle (penting bila library dikompilasi dengan C++). Kita buat libmatema dengan tiga fungsi: mate_tambah, mate_rata_rata, mate_versi.
/* File: libmatema.h - deklarasi untuk konsumsi Python */
#ifndef LIBMATEMA_H
#define LIBMATEMA_H
#ifdef __cplusplus
extern "C" {
#endif
int mate_tambah(int a, int b);
double mate_rata_rata(const double *arr, int n);
const char *mate_versi(void);
#ifdef __cplusplus
}
#endif
#endif /* LIBMATEMA_H *//* File: libmatema.c - implementasi */
#include "libmatema.h"
int mate_tambah(int a, int b) {
return a + b;
}
double mate_rata_rata(const double *arr, int n) {
if (n <= 0 || !arr) return 0.0;
double total = 0.0;
for (int i = 0; i < n; i++) total += arr[i];
return total / (double) n;
}
const char *mate_versi(void) {
return "libmatema 1.0.0";
}Compile menjadi shared library:
gcc -std=c11 -Wall -Wextra -fPIC -shared -o libmatema.so libmatema.c
ls -la libmatema.soOutput yang Dihasilkan:
-rwxrwxr-x 1 z z 15168 Oct 13 09:02 libmatema.soMari kita telaah baris-baris kode di atas:
- Baris 4-6 (
#ifdef __cplusplus extern "C"): Wajib bila library akan dipanggil dari Python ctypes. Tanpa block ini, bila library dikompilasi dengang++(bukangcc), symbolmate_tambahberubah menjadi_Z11mate_tambahii(gaya Itanium ABI C++).ctypes.CDLLmencarimate_tambahpersis dan akan gagal. - Baris 13 (
const double *arr, int n): Fungsi menerima pointer ke arraydoubleplus panjang. Pola ini umum di C—Python harus mengirimkan array lewatctypes.POINTER(ctypes.c_double). - Flag
-fPIC -shared: Sama seperti chapter Shared Library Interfaces.-fPICmenghasilkan Position Independent Code,-sharedmenghasilkan shared object.
Memanggil dari Python dengan ctypes #
Modul ctypes adalah modul built-in Python yang memuat .so/.dll dan memetakan tipe C ke tipe Python. Tiga langkah utama: (1) muat library, (2) nyatakan tipe argumen dan return value (opsional tapi disarankan), (3) panggil fungsi seperti fungsi Python biasa.
#!/usr/bin/env python3
# File: py_panggil.py - memanggil libmatema.so lewat ctypes
import ctypes
# Muat shared library (absolut atau relatif)
lib = ctypes.CDLL("./libmatema.so")
# Tentukan tipe argumen dan return value
lib.mate_tambah.argtypes = [ctypes.c_int, ctypes.c_int]
lib.mate_tambah.restype = ctypes.c_int
lib.mate_versi.argtypes = []
lib.mate_versi.restype = ctypes.c_char_p
lib.mate_rata_rata.argtypes = [ctypes.POINTER(ctypes.c_double), ctypes.c_int]
lib.mate_rata_rata.restype = ctypes.c_double
# 1. Panggil fungsi integer
hasil = lib.mate_tambah(17, 25)
print(f"17 + 25 = {hasil}")
# 2. Panggil fungsi yang return string
versi = lib.mate_versi().decode("utf-8")
print(f"Versi: {versi}")
# 3. Panggil fungsi yang menerima array
data = (ctypes.c_double * 4)(10.0, 20.0, 30.0, 40.0)
rata = lib.mate_rata_rata(data, 4)
print(f"Rata-rata [10,20,30,40] = {rata}")Jalankan Python:
python3 py_panggil.pyOutput yang Dihasilkan:
17 + 25 = 42
Versi: libmatema 1.0.0
Rata-rata [10,20,30,40] = 25.0Mari kita telaah baris-baris kode di atas:
- Baris 5 (
ctypes.CDLL("./libmatema.so")): Memuat shared library dan mengembalikan objekCDLL. Setiap fungsi global di library menjadi atribut objek—lib.mate_tambah,lib.mate_versi, dst. Bila library tidak ditemukan, Python memunculkanOSError. Path dapat absolut (/usr/lib/libfoo.so) atau relatif (./libmatema.so); gunakanctypes.util.find_library("matema")untuk pencarian otomatis. - Baris 8-9 (
argtypesdanrestype): Menyatakan tipe argumen dan return value. Tanpa deklarasi ini,ctypesmengasumsikanintuntuk keduanya—bila return value adalahdoubleatauchar *, hasil akan salah (misalnya mengembalikan integer acak). Mendeklarasikanargtypesjuga membuatctypesmelakukan type checking dan mengkonversi otomatis (misalnya Pythonint→c_int). - Baris 12 (
restype = ctypes.c_char_p): Memberi tahuctypesbahwa fungsi mengembalikanconst char *. Python akan menerima objekbytes(bukanstr), jadi kita perlu.decode("utf-8")di baris 22 untuk mendapat string Python. - Baris 21 (
(ctypes.c_double * 4)(...)): Membuat array Cdouble[4]dan mengisinya. Konstruktor menerima daftar nilai. Objek ini kompatibel denganconst double *di sisi C—ctypesotomatis mengkonversic_double_Array_4kePOINTER(c_double). - Baris 22 (
lib.mate_rata_rata(data, 4)): Memanggil fungsi C dengan array dan panjang. Hasildoubleotomatis menjadi Pythonfloat. Loop numerik di C jauh lebih cepat daripada di Python murni, sehingga pola ini sering dipakai untuk akselerasi.
Tiga Pendekatan FFI Python #
ctypes bukan satu-satunya pilihan. Berikut ringkasan tiga pendekatan utama:
| Pendekatan | Cara Kerja | Kelebihan | Kekurangan |
|---|---|---|---|
ctypes | Memuat .so saat runtime; deklarasi tipe di Python | Built-in Python, no compile | Lambat untuk call sering; manual tipe |
cffi | Mirip ctypes tetapi deklarasi tipe dari C header | Lebih cepat, ABI-like API, dapat memakai header asli | Butuh instalasi cffi |
| CPython extension | Modul native lewat Python C API | Paling cepat, integrasi penuh | Butuh compile, kompleks |
Untuk sebagian besar kasus, ctypes sudah cukup. cffi dipakai oleh library seperti pyOpenSSL yang membungkus banyak fungsi. CPython extension dipakai bila Anda perlu integrasi sangat ketat (misalnya NumPy, yang mendefinisikan tipe array baru di sisi Python).