Last Updated on January 24, 2023 by
Ada beberapa cara untuk memperluas fungsionalitas Python. Salah satunya adalah menulis modul Python extensions Anda di C atau C++ . Proses ini dapat menghasilkan peningkatan kinerja dan akses yang lebih baik ke fungsi pustaka C dan panggilan sistem. Dalam tutorial ini, Anda akan menemukan cara menggunakan API Python untuk menulis modul ekstensi Python C.
Table of Contents
Python Extensions Program
Salah satu fitur Python yang kurang dikenal namun sangat kuat adalah kemampuannya untuk memanggil fungsi dan pustaka yang didefinisikan dalam bahasa yang dikompilasi seperti C atau C++. Ini memungkinkan Anda untuk memperluas kemampuan program Anda melebihi apa yang ditawarkan oleh fitur bawaan Python.
Ada banyak bahasa yang dapat Anda pilih untuk fungsionalitas Python extensions. Jadi, mengapa Anda harus menggunakan C? Berikut adalah beberapa alasan mengapa Anda mungkin memutuskan untuk membangun modul ekstensi Python C:
- Untuk mengimplementasikan tipe objek bawaan baru: Dimungkinkan untuk menulis kelas Python di C, lalu membuat instance dan memperluas kelas itu dari Python itu sendiri. Ada banyak alasan untuk melakukan ini, tetapi lebih sering daripada tidak, kinerja terutama yang mendorong pengembang untuk beralih ke C. Situasi seperti itu jarang terjadi, tetapi ada baiknya untuk mengetahui sejauh mana Python dapat diperluas.
- Untuk memanggil fungsi pustaka C dan panggilan sistem: Banyak bahasa pemrograman menyediakan antarmuka ke panggilan sistem yang paling umum digunakan. Namun, mungkin ada panggilan sistem lain yang jarang digunakan yang hanya dapat diakses melalui C. osModul dalam Python adalah salah satu contohnya.
Ini bukan daftar lengkap, tetapi memberi Anda inti dari apa yang bisa dilakukan saat memperluas Python menggunakan C atau bahasa lainnya.
Untuk menulis modul Python di C, Anda harus menggunakan Python API , yang mendefinisikan berbagai fungsi, makro, dan variabel yang memungkinkan juru bahasa Python memanggil kode C Anda.
Menulis Interface Python extensions di C
Dalam tutorial ini, Anda akan menulis wrapper kecil untuk fungsi pustaka C , yang kemudian akan Anda panggil dari dalam Python. Menerapkan wrapper sendiri akan memberi Anda ide yang lebih baik tentang kapan dan bagaimana menggunakan C untuk memperluas modul Python Anda.
Memahami FPuts
FPuts adalah fungsi pustaka C yang akan Anda Wrap :
int fputs(const char *, FILE *)
Fungsi ini membutuhkan dua argumen:
- const char * adalah array dari karakter.
- FILE * adalah penunjuk aliran file.
fputs() menulis array karakter ke file yang ditentukan oleh aliran file dan mengembalikan nilai non-negatif. Jika operasi berhasil, maka nilai ini akan menunjukkan jumlah byte yang ditulis ke file. Jika ada kesalahan, maka kembali EOF.
Menulis Fungsi C untuk fPuts() Python Extensions
Ini adalah program C dasar yang digunakan fputs() untuk menulis string ke aliran file:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> int main() { FILE *fp = fopen("write.txt", "w"); fputs("Real Python!", fp); fclose(fp); return 1; }
Cuplikan kode ini dapat diringkas sebagai berikut:
- Bukafile txt.
- Tulisstring “Real Python!”ke file.
Wrapping fputs()
Mungkin agak aneh melihat kode lengkap sebelum penjelasan tentang cara kerjanya. Namun, meluangkan waktu sejenak untuk memeriksa produk akhir akan menambah pemahaman Anda di bagian berikut. Blok kode di bawah ini menunjukkan versi terakhir dari kode C Anda:
#include <Python.h> static PyObject *method_fputs(PyObject *self, PyObject *args) { char *str, *filename = NULL; int bytes_copied = -1; /* Parse arguments */ if(!PyArg_ParseTuple(args, "ss", &str, &filename)) { return NULL; } FILE *fp = fopen(filename, "w"); bytes_copied = fputs(str, fp); fclose(fp); return PyLong_FromLong(bytes_copied); }
Cuplikan kode ini mereferensikan tiga struktur objek yang didefinisikan dalam Python.h:
- PyObject
- PyArg_ParseTuple()
- PyLong_FromLong()
Ini digunakan untuk definisi tipe data untuk bahasa Python. Anda akan membahasnya masing-masing sekarang.
PyObject
PyObject adalah struktur objek yang Anda gunakan untuk mendefinisikan tipe objek untuk Python. Semua objek Python berbagi sejumlah kecil bidang yang ditentukan menggunakan PyObject struktur. Semua tipe objek lainnya adalah ekstensi dari tipe ini.
PyObject memberi tahu juru bahasa Python untuk memperlakukan penunjuk ke objek sebagai objek. Misalnya, menyetel tipe kembalian dari fungsi diatas sebagai PyObject mendefinisikan bidang umum yang diperlukan oleh juru bahasa Python untuk mengenali ini sebagai tipe Python yang valid.
Perhatikan lagi beberapa baris pertama kode C Anda:
static PyObject *method_fputs(PyObject *self, PyObject *args) { char *str, *filename = NULL; int bytes_copied = -1; /* Snip */
Pada baris 2, Anda mendeklarasikan tipe argumen yang ingin Anda terima dari kode Python Anda:
- char *str adalah string yang ingin Anda tulis ke aliran file.
- char *filename adalah nama file yang akan ditulis.
PyArg_ParseTuple()
PyArg_ParseTuple() mem-parsing argumen yang akan Anda terima dari program Python ke dalam variabel lokal:
static PyObject *method_fputs(PyObject *self, PyObject *args) { char *str, *filename = NULL; int bytes_copied = -1; /* Parse arguments */ if(!PyArg_ParseTuple(args, "ss", &str, &filename)) { return NULL; } /* Snip */
Jika Anda melihat baris 6, maka Anda akan melihat bahwa PyArg_ParseTuple() dibutuhkan argumen berikut :
- args adalah tipe PyObject.
- “ss” adalah penentu format yang menentukan tipe data dari argumen yang akan diuraikan. (Anda dapat melihat dokumentasi resmi untuk referensi lengkap.)
- &str dan &filename merupakan penunjuk ke variabel lokal yang akan diberi nilai parsing.
PyArg_ParseTuple() mengevaluasi false kegagalan. Jika gagal, maka fungsi akan kembali NULL dan tidak melanjutkan lebih jauh.
PyLong_FromLong(bytes_copied)
PyLong_FromLong() mengembalikan sebuah PyLongObject, yang mewakili objek bilangan bulat dengan Python. Anda dapat menemukannya di akhir kode C Anda:
static PyObject *method_fputs(PyObject *self, PyObject *args) { char *str, *filename = NULL; int bytes_copied = -1; /* Parse arguments */ if(!PyArg_ParseTuple(args, "ss", &str, &filename)) { return NULL; } FILE *fp = fopen(filename, "w"); bytes_copied = fputs(str, fp); fclose(fp); return PyLong_FromLong(bytes_copied); }
Baris 14 menghasilkan PyLongObject untuk bytes_copied, variabel yang akan dikembalikan saat fungsi dipanggil dengan Python. Anda harus mengembalikan PyObject* dari modul ekstensi Python C Anda kembali ke juru bahasa Python.
Menulis Fungsi Init
Anda telah menulis kode yang membentuk fungsionalitas inti dari modul Python extensions C Anda. Namun, masih ada beberapa fungsi tambahan yang diperlukan untuk mengaktifkan dan menjalankan modul Anda. Anda harus menulis definisi modul Anda dan metode yang ada di dalamnya, seperti :
static PyMethodDef FputsMethods[] = { {"fputs", method_fputs, METH_VARARGS, "Python interface for fputs C library function"}, {NULL, NULL, 0, NULL} }; static struct PyModuleDef fputsmodule = { PyModuleDef_HEAD_INIT, "fputs", "Python interface for the fputs C library function", -1, FputsMethods };
Fungsi ini menyertakan informasi meta tentang modul Anda yang akan digunakan oleh juru bahasa Python.
PyMethodDef
Untuk memanggil metode yang didefinisikan dalam modul Anda, Anda harus memberi tahu juru bahasa Python tentangnya terlebih dahulu. Untuk melakukan ini, Anda dapat menggunakan PyMethodDef. Ini adalah struktur dengan 4 anggota yang mewakili satu metode dalam modul Anda.
Idealnya, akan ada lebih dari satu metode dalam modul ekstensi Python C yang ingin Anda panggil dari juru bahasa Python. Inilah sebabnya mengapa Anda perlu mendefinisikan array PyMethodDefstruct:
static PyMethodDef FputsMethods[] = { {"fputs", method_fputs, METH_VARARGS, "Python interface for fputs C library function"}, {NULL, NULL, 0, NULL} };
Setiap anggota individu dari struct memegang info berikut:
- “fputs” adalah nama yang akan ditulis pengguna untuk menjalankan fungsi khusus ini.
- method_fputs adalah nama fungsi C yang akan dipanggil.
- METH_VARARGS adalah sebuah flag yang memberitahu interpreter bahwa fungsi akan menerima dua argumen tipe PyObject*:
- Self adalah objek modul.
- Args adalah tuple yang berisi argumen sebenarnya untuk fungsi Anda. Seperti yang dijelaskan sebelumnya, argumen ini dibongkar menggunakan PyArg_ParseTuple().
- String terakhir adalah nilai yang mewakili metode docstring .
PyModuleDef
Sama seperti PyMethodDef menyimpan informasi tentang metode dalam modul ekstensi Python C Anda, PyModuleDefstruct menyimpan informasi tentang modul Anda sendiri. Ini bukan susunan struktur, melainkan struktur tunggal yang digunakan untuk definisi modul:
static struct PyModuleDef fputsmodule = { PyModuleDef_HEAD_INIT, "fputs", "Python interface for the fputs C library function", -1, FputsMethods };
Ada total 9 anggota dalam struktur ini, tetapi tidak semuanya diperlukan. Di blok kode di atas, Anda menginisialisasi lima berikut:
- PyModuleDef_HEAD_INIT adalah anggota dari type PyModuleDef_Base, yang disarankan untuk memiliki nilai yang satu ini saja.
- “fputs” adalah nama modul ekstensi Python C Anda.
- String adalah nilai yang mewakili docstring modul Anda. Anda dapat menggunakan NULL untuk tidak memiliki docstring, atau Anda dapat menentukan docstring dengan meneruskan a const char *seperti yang ditampilkan dalam cuplikan di atas. Ini adalah jenis Py_ssize_t. Anda juga dapat menggunakan PyDoc_STRVAR()untuk menentukan docstring untuk modul Anda.
- -1 adalah jumlah memori yang diperlukan untuk menyimpan status program Anda. Akan sangat membantu jika modul Anda digunakan di beberapa sub-penerjemah, dan dapat memiliki nilai berikut:
- Nilai negatif menunjukkan bahwa modul ini tidak mendukung sub-interpreter.
- Nilai non-negatif memungkinkan inisialisasi ulang modul Anda. Itu juga menentukan persyaratan memori modul Anda untuk dialokasikan pada setiap sesi sub-interpreter.
- FputsMethods adalah referensi ke tabel metode Anda. Ini adalah larik PyMethodDefstruct yang Anda tentukan sebelumnya.
PyMODINIT_FUNC
Sekarang setelah Anda mendefinisikan modul ekstensi Python C dan struktur metode, saatnya untuk menggunakannya. Saat program Python mengimpor modul Anda untuk pertama kalinya, ia akan memanggil PyInit_fputs():
PyMODINIT_FUNC PyInit_fputs(void) { return PyModule_Create(&fputsmodule); }
PyMODINIT_FUNC melakukan 3 hal secara implisit ketika dinyatakan sebagai tipe pengembalian fungsi:
- Ini secara implisit menetapkan tipe kembalian dari fungsi sebagai PyObject*.
- Ini menyatakan setiap hubungan khusus.
- Ini mendeklarasikan fungsi sebagai extern “C.” Jika Anda menggunakan C++, ia memberi tahu kompiler C++ untuk tidak melakukan perusakan nama pada simbol.
PyModule_Create() akan mengembalikan objek modul baru bertipe PyObject *. Untuk argumen, Anda akan meneruskan alamat struktur metode yang sudah Anda tentukan sebelumnya, fputs module.
Menyatukan Semua Menjadi Modul Python Extensions
Sekarang setelah Anda menulis bagian-bagian yang diperlukan dari modul Python extensions C Anda, mari mundur selangkah untuk melihat bagaimana semuanya cocok satu sama lain.
Saat Anda mengimpor modul ekstensi Python C Anda, PyInit_fputs() adalah metode pertama yang dipanggil. Namun, sebelum referensi dikembalikan ke juru bahasa Python, fungsi membuat panggilan berikutnya ke PyModule_Create(). Ini akan menginisialisasi struktur PyModuleDef dan PyMethodDef, yang menyimpan informasi meta tentang modul Anda. Masuk akal untuk menyiapkannya karena Anda akan menggunakannya dalam fungsi init Anda.
Setelah ini selesai, referensi ke objek modul akhirnya dikembalikan ke juru bahasa Python.
Objek modul yang dikembalikan oleh PyModule_Create() memiliki referensi ke struktur modul PyModuleDef, yang pada gilirannya memiliki referensi ke tabel metode PyMethodDef. Saat Anda memanggil metode yang ditentukan dalam modul ekstensi Python C Anda, juru bahasa Python menggunakan objek modul dan semua referensi yang dibawanya untuk mengeksekusi metode tertentu. (Meskipun ini bukan cara juru bahasa Python menangani hal-hal di bawah tenda, ini akan memberi Anda gambaran tentang cara kerjanya.)
Demikian pula, Anda dapat mengakses berbagai metode dan properti lain dari modul Anda, seperti modul docstring atau metode docstring. Ini didefinisikan di dalam struktur masing-masing.
Sekarang Anda memiliki gambaran tentang apa yang terjadi saat Anda memanggil fputs() dari juru bahasa Python. Penerjemah menggunakan objek modul Anda serta modul dan metode referensi untuk memanggil metodenya.
Setelah method_fputs() dipanggil, program menjalankan langkah-langkah berikut:
- Parsing argumen yang Anda berikan dari juru bahasa PythonPyArg_ParseTuple()
- Sampaikan argumen ini ke fputs(), fungsi pustaka C yang membentuk inti dari modul Anda
- Gunakan PyLong_FromLong untuk mengembalikan nilai darifputs()
Untuk melihat langkah-langkah yang sama dalam kode, lihat method_fputs() lagi:
static PyObject *method_fputs(PyObject *self, PyObject *args) { char *str, *filename = NULL; int bytes_copied = -1; /* Parse arguments */ if(!PyArg_ParseTuple(args, "ss", &str, &filename)) { return NULL; } FILE *fp = fopen(filename, "w"); bytes_copied = fputs(str, fp); fclose(fp); return PyLong_FromLong(bytes_copied); }
Singkatnya, metode Anda akan mengurai argumen yang diteruskan ke modul Anda, mengirimkannya ke fputs(), dan mengembalikan hasilnya.
Temukan lebih banyak artikel seri belajar Python maupun bahasa pemrograman lainnya hanya di CODEKEY. Klik https://codekey.id/ sekarang juga untuk langsung belajar gratis. Sampai bertemu lagi!
Jasa Pembuatan Aplikasi, Website dan Internet Marketing | PT APPKEY
PT APPKEY adalah perusahaan IT yang khusus membuat aplikasi Android, iOS dan mengembangkan sistem website. Kami juga memiliki pengetahuan dan wawasan dalam menjalankan pemasaran online sehingga diharapkan dapat membantu menyelesaikan permasalahan Anda.