Manufaktur industri
Industri Internet of Things | bahan industri | Pemeliharaan dan Perbaikan Peralatan | Pemrograman industri |
home  MfgRobots >> Manufaktur industri >  >> Industrial programming >> Python

Pemrograman Ekstensi Python dengan C: Bangun Modul Asli Cepat

Halaman Sebelumnya Halaman Berikutnya  

Kode apa pun yang Anda tulis menggunakan bahasa terkompilasi seperti C, C++, atau Java dapat diintegrasikan atau diimpor ke dalam skrip Python lain. Kode ini dianggap sebagai "ekstensi."

Sebuah modul ekstensi Python tidak lebih dari perpustakaan C biasa. Pada mesin Unix, perpustakaan ini biasanya berakhir dengan .so (untuk objek bersama). Pada mesin Windows, biasanya Anda melihat .dll (untuk perpustakaan yang ditautkan secara dinamis).

Prasyarat untuk Menulis Ekstensi

Untuk mulai menulis ekstensi Anda, Anda akan membutuhkan file header Python.

Selain itu, diasumsikan Anda memiliki pengetahuan yang baik tentang C atau C++ untuk menulis Ekstensi Python apa pun menggunakan pemrograman C.

Pertama Kali Melihat Ekstensi Python

Untuk pertama kalinya melihat modul ekstensi Python, Anda perlu mengelompokkan kode Anda ke dalam empat bagian −

File Header Python.h

Anda perlu menyertakan file header Python.h dalam file sumber C Anda, yang memberi Anda akses ke API internal Python yang digunakan untuk menghubungkan modul Anda ke interpreter.

Pastikan untuk menyertakan Python.h sebelum header lain yang mungkin Anda butuhkan. Anda perlu mengikuti includes dengan fungsi yang ingin Anda panggil dari Python.

Fungsi C

Tanda tangan implementasi C dari fungsi Anda selalu mengambil salah satu dari tiga bentuk berikut −

 static PyObject *MyFunction( PyObject *self, PyObject *args ); static PyObject *MyFunctionWithKeywords(PyObject *self, PyObject *args, PyObject *kw); static PyObject *MyFunctionWithNoArgs( PyObject *self ); 

Setiap deklarasi di atas mengembalikan objek Python. Tidak ada hal yang disebut fungsi void dalam Python seperti yang ada di C. Jika Anda tidak ingin fungsi Anda mengembalikan nilai, kembalikan setara C dari nilai None Python. Header Python mendefinisikan makro, Py_RETURN_NONE, yang melakukan ini untuk kita.

Nama fungsi C Anda dapat apa pun yang Anda sukai karena tidak pernah dilihat di luar modul ekstensi. Mereka didefinisikan sebagai fungsi static.

Fungsi C Anda biasanya dinamakan dengan menggabungkan nama modul dan fungsi Python bersama-sama, seperti yang ditunjukkan di sini −

 static PyObject *module_func(PyObject *self, PyObject *args) { /* Lakukan hal Anda di sini. */ Py_RETURN_NONE; } 

Ini adalah fungsi Python yang disebut func di dalam modul module. Anda akan meletakkan pointer ke fungsi C Anda ke dalam tabel metode untuk modul yang biasanya datang selanjutnya dalam kode sumber Anda.

Tabel Pemetaan Metode

Tabel metode ini adalah array sederhana dari struktur PyMethodDef. Struktur tersebut terlihat seperti ini −

 struct PyMethodDef { char *ml_name; PyCFunction ml_meth; int ml_flags; char *ml_doc; }; 

Berikut adalah deskripsi anggota struktur ini −

Tabel ini perlu diakhiri dengan sentinel yang terdiri dari nilai NULL dan 0 untuk anggota yang sesuai.

Contoh

Untuk fungsi yang telah didefinisikan di atas, kita memiliki tabel pemetaan metode berikut −

 static PyMethodDef module_methods[] = { { "func", (PyCFunction)module_func, METH_NOARGS, NULL }, { NULL, NULL, 0, NULL } }; 

Fungsi Inisialisasi

Bagian terakhir dari modul ekstensi Anda adalah fungsi inisialisasi. Fungsi ini dipanggil oleh interpreter Python saat modul dimuat. Diperlukan agar fungsi dinamakan initModule, di mana Module adalah nama modul.

Fungsi inisialisasi perlu diekspor dari perpustakaan yang akan Anda bangun. Header Python mendefinisikan PyMODINIT_FUNC untuk menyertakan mantra yang sesuai agar ini dapat terjadi untuk lingkungan tertentu tempat kita mengompilasi. Yang perlu Anda lakukan adalah menggunakannya saat mendefinisikan fungsi.

Fungsi inisialisasi C Anda umumnya memiliki struktur keseluruhan berikut −

 PyMODINIT_FUNC initModule() { Py_InitModule3(func, module_methods, "docstring..."); } 

Berikut adalah deskripsi fungsi Py_InitModule3 −

Menggabungkan semuanya terlihat seperti berikut −

 #include <Python.h> static PyObject *module_func(PyObject *self, PyObject *args) { /* Lakukan hal Anda di sini. */ Py_RETURN_NONE; } static PyMethodDef module_methods[] = { { "func", (PyCFunction)module_func, METH_NOARGS, NULL }, { NULL, NULL, 0, NULL } }; PyMODINIT_FUNC initModule() { Py_InitModule3(func, module_methods, "docstring..."); } 

Contoh

Contoh sederhana yang menggunakan semua konsep di atas −

 #include <Python.h> static PyObject* helloworld(PyObject* self) { return Py_BuildValue("s", "Hello, Python extensions!!"); } static char helloworld_docs[] = "helloworld( ): Any message you want to put here!!\n"; static PyMethodDef helloworld_funcs[] = {{"helloworld", (PyCFunction)helloworld, METH_NOARGS, helloworld_docs}, {NULL} }; void inithelloworld(void) { Py_InitModule3("helloworld", helloworld_funcs, "Extension module example!"); } 

Di sini fungsi Py_BuildValue digunakan untuk membuat nilai Python. Simpan kode di atas dalam file hello.c. Kita akan melihat cara mengompilasi dan menginstal modul ini untuk dipanggil dari skrip Python.

Membangun dan Menginstal Ekstensi

Paket distutils membuatnya sangat mudah untuk mendistribusikan modul Python, baik murni Python maupun modul ekstensi, dengan cara standar. Modul didistribusikan dalam bentuk sumber dan dibangun serta diinstal melalui skrip setup yang biasanya disebut setup.py sebagai berikut.

Untuk modul di atas, Anda perlu menyiapkan skrip setup.py berikut −

 from distutils.core import setup, Extension setup(name='helloworld', version='1.0', \ ext_modules=[Extension('helloworld', ['hello.c'])]) 

Sekarang, gunakan perintah berikut, yang akan melakukan semua langkah kompilasi dan penautan yang diperlukan, dengan perintah dan flag kompiler serta penaut yang tepat, dan menyalin perpustakaan dinamis yang dihasilkan ke direktori yang sesuai −

 $ python setup.py install 

Pada sistem berbasis Unix, kemungkinan besar Anda perlu menjalankan perintah ini sebagai root untuk memiliki izin menulis ke direktori site-packages. Biasanya ini bukan masalah pada Windows.

Mengimpor Ekstensi

Setelah Anda menginstal ekstensi Anda, Anda akan dapat mengimpor dan memanggil ekstensi tersebut dalam skrip Python Anda sebagai berikut −

 #!/usr/bin/python import helloworld print helloworld.helloworld() 

Ini akan menghasilkan hasil berikut −

 Hello, Python extensions!! 

Melewatkan Parameter Fungsi

Seperti yang Anda kemungkinan inginkan untuk mendefinisikan fungsi yang menerima argumen, Anda dapat menggunakan salah satu tanda tangan lain untuk fungsi C Anda. Misalnya, fungsi berikut, yang menerima sejumlah parameter, akan didefinisikan seperti ini −

 static PyObject *module_func(PyObject *self, PyObject *args) { /* Parse args dan lakukan sesuatu yang menarik di sini. */ Py_RETURN_NONE; } 

Tabel metode yang berisi entri untuk fungsi baru akan terlihat seperti ini −

 static PyMethodDef module_methods[] = { { "func", (PyCFunction)module_func, METH_NOARGS, NULL }, { "func", module_func, METH_VARARGS, NULL }, { NULL, NULL, 0, NULL } }; 

Anda dapat menggunakan fungsi API PyArg_ParseTuple untuk mengekstrak argumen dari pointer PyObject yang diteruskan ke dalam fungsi C Anda.

Argumen pertama untuk PyArg_ParseTuple adalah argumen args. Ini adalah objek yang akan Anda parsing. Argumen kedua adalah string format yang menggambarkan argumen seperti yang Anda harapkan mereka muncul. Setiap argumen direpresentasikan oleh satu atau lebih karakter dalam string format sebagai berikut.

 static PyObject *module_func(PyObject *self, PyObject *args) { int i; double d; char *s; if (!PyArg_ParseTuple(args, "ids", &i, &d, &s)) { return NULL; } /* Lakukan sesuatu yang menarik di sini. */ Py_RETURN_NONE; } 

Mengompilasi versi baru modul Anda dan mengimpornya memungkinkan Anda untuk memanggil fungsi baru dengan sejumlah argumen apa pun dari tipe apa pun −

 module.func(1, s="three", d=2.0) module.func(i=1, d=2.0, s="three") module.func(s="three", d=2.0, i=1) 

Anda mungkin dapat menghasilkan variasi lebih banyak lagi.

Fungsi PyArg_ParseTuple

Berikut adalah tanda tangan standar untuk fungsi PyArg_ParseTuple −

 int PyArg_ParseTuple(PyObject* tuple,char* format,...) 

Fungsi ini mengembalikan 0 untuk error, dan nilai yang tidak sama dengan 0 untuk kesuksesan. tuple adalah PyObject* yang merupakan argumen kedua dari fungsi C. Di sini format adalah string C yang menggambarkan argumen wajib dan opsional.

Berikut adalah daftar kode format untuk fungsi PyArg_ParseTuple −

Kode Tipe C Arti
c char Sebuah string Python panjang 1 menjadi C char.
d double Sebuah float Python menjadi C double.
f float Sebuah float Python menjadi C float.
i int Sebuah int Python menjadi C int.
l long Sebuah int Python menjadi C long.
L long long Sebuah int Python menjadi C long long
O PyObject* Mendapatkan referensi pinjaman non-NULL ke argumen Python.
s char* String Python tanpa null tersemat ke C char*.
s# char*+int String Python apa pun ke alamat dan panjang C.
t# char*+int Buffer segmen tunggal hanya baca ke alamat dan panjang C.
u Py_UNICODE* Python Unicode tanpa null tersemat ke C.
u# Py_UNICODE*+int Python Unicode apa pun alamat dan panjang C.
w# char*+int Buffer segmen tunggal baca/tulis ke alamat dan panjang C.
z char* Seperti s, juga menerima None (mengatur C char* ke NULL).
z# char*+int Seperti s#, juga menerima None (mengatur C char* ke NULL).
(...) as per ... Urutan Python diperlakukan sebagai satu argumen per item.
|   Argumen berikutnya adalah opsional.
:   Akhir format, diikuti oleh nama fungsi untuk pesan error.
;   Akhir format, diikuti oleh seluruh teks pesan error.

Mengembalikan Nilai

Py_BuildValue menerima string format seperti yang dilakukan PyArg_ParseTuple. Alih-alih meneruskan alamat nilai yang Anda bangun, Anda meneruskan nilai aktual. Berikut adalah contoh yang menunjukkan cara mengimplementasikan fungsi tambah −

 static PyObject *foo_add(PyObject *self, PyObject *args) { int a; int b; if (!PyArg_ParseTuple(args, "ii", &a, &b)) { return NULL; } return Py_BuildValue("i", a + b); } 

Ini adalah apa yang akan terlihat jika diimplementasikan dalam Python −

 def add(a, b): return (a + b) 

Anda dapat mengembalikan dua nilai dari fungsi Anda sebagai berikut, ini akan ditangkap menggunakan daftar dalam Python.

 static PyObject *foo_add_subtract(PyObject *self, PyObject *args) { int a; int b; if (!PyArg_ParseTuple(args, "ii", &a, &b)) { return NULL; } return Py_BuildValue("ii", a + b, a - b); } 

Ini adalah apa yang akan terlihat jika diimplementasikan dalam Python −

 def add_subtract(a, b): return (a + b, a - b) 

Fungsi Py_BuildValue

Berikut adalah tanda tangan standar untuk fungsi Py_BuildValue −

 PyObject* Py_BuildValue(char* format,...) 

Di sini format adalah string C yang menggambarkan objek Python yang akan dibuat. Argumen berikutnya dari Py_BuildValue adalah nilai C yang digunakan untuk membangun hasil. Hasil PyObject* adalah referensi baru.

Tabel berikut mencantumkan string kode yang sering digunakan, nol atau lebih digabungkan menjadi string format.

Kode Tipe C Arti
c char Sebuah C char menjadi string Python panjang 1.
d double Sebuah C double menjadi float Python.
f float Sebuah C float menjadi float Python.
i int Sebuah C int menjadi int Python.
l long Sebuah C long menjadi int Python.
N PyObject* Mengirim objek Python dan mencuri referensi.
O PyObject* Mengirim objek Python dan INCREF-nya seperti biasa.
O& convert+void* Konversi sembarang
s char* C 0-terminated char* ke string Python, atau NULL ke None.
s# char*+int C char* dan panjang ke string Python, atau NULL ke None.
u Py_UNICODE* String C-wide, null-terminated ke Unicode Python, atau NULL ke None.
u# Py_UNICODE*+int String C-wide dan panjang ke Unicode Python, atau NULL ke None.
w# char*+int Buffer segmen tunggal baca/tulis ke alamat dan panjang C.
z char* Seperti s, juga menerima None (mengatur C char* ke NULL).
z# char*+int Seperti s#, juga menerima None (mengatur C char* ke NULL).
(...) as per ... Membangun tuple Python dari nilai C.
[...] as per ... Membangun daftar Python dari nilai C.
{...} as per ... Membangun kamus Python dari nilai C, secara bergantian kunci dan nilai.

Kode {...} membangun kamus dari sejumlah nilai C yang genap, secara bergantian kunci dan nilai. Misalnya, Py_BuildValue("{issi}",23,"zig","zag",42) mengembalikan kamus seperti Python {23:'zig','zag':42}.


Python

  1. Menguasai Pemrograman Berorientasi Objek Python: Kelas, Warisan, Enkapsulasi & Polimorfisme
  2. Fungsi print() Python: Panduan Praktis dengan Contoh
  3. Menguasai Metode strip() Python: Panduan Lengkap & Contoh Praktis
  4. Menguasai str.count() Python: Cara Menghitung Karakter & Substring dengan Contoh
  5. Menguasai String `format()` Python dengan Contoh Jelas
  6. Menguasai Metode String.find() Python: Sintaks, Contoh & Alternatif
  7. Menguasai Fungsi Lambda Python: Contoh Praktis & Praktik Terbaik
  8. Fungsi round() Python Dijelaskan dengan Contoh Praktis
  9. Menguasai Fungsi map() Python: Sintaks, Contoh, dan Praktik Terbaik
  10. Python timeit() – Mengukur Waktu Eksekusi dengan Contoh Praktis