ctypes - Pemula

100

Saya memiliki tugas untuk "membungkus" perpustakaan ac menjadi kelas python. Dokumen sangat tidak jelas tentang masalah ini. Tampaknya mereka mengharapkan hanya pengguna python tingkat lanjut yang akan mengimplementasikan ctypes. Saya seorang pemula dalam python dan butuh bantuan.

Beberapa bantuan langkah demi langkah akan sangat bagus.

Jadi saya memiliki perpustakaan c saya. Apa yang saya lakukan? File apa yang saya taruh di mana? Bagaimana cara mengimpor perpustakaan? Saya membaca bahwa mungkin ada cara untuk "bungkus otomatis" ke Python?

(Ngomong-ngomong saya melakukan tutorial ctypes di python.net dan itu tidak berhasil. Artinya saya berpikir mereka berasumsi bahwa saya harus dapat mengisi langkah-langkah selanjutnya.

Sebenarnya ini adalah kesalahan yang saya dapatkan dengan kode mereka:

File "importtest.py", line 1
   >>> from ctypes import *
   SyntaxError: invalid syntax

Saya benar-benar dapat menggunakan bantuan langkah demi langkah untuk ini! Terima kasih ~

menghabiskan
sumber
10
Apakah Anda memiliki >>> in importtest.py? Ketika orang memposting kode yang ada >>> di setiap baris, itu menandakan bahwa itu sedang dijalankan di shell interaktif. Untuk menjalankannya dari file, hapus >>> (yaitu 3> tanda dan spasi) di mana pun ia muncul.
Chinmay Kanchi
4
Jangan ketik >>>s. Itu dicetak oleh shell interaktif dan harus ditinggalkan dari file sumber Anda.
nmichaels
8
>>>di file .py! ADUH! Belum pernah melihat itu sebelumnya!
David Heffernan
3
Sejujurnya, pelajari sedikit Python (setidaknya sedikit) sebelum Anda mulai mengotak-atik ctypes. Anda tidak akan pernah menemukan tutorial tentang ctypes yang mengasumsikan Anda tidak tahu Python dasar.
Chinmay Kanchi
3
@spentak: jika Anda meminta bantuan, berikan informasi yang memadai. Setidaknya tunjukkan kepada kami versi terakhir dari kode yang Anda bicarakan. Apa yang ada di "baris 3", misalnya?
Francesco

Jawaban:

228

Berikut tutorial ctypes cepat dan kotor.

Pertama, tulis perpustakaan C Anda. Berikut contoh sederhana Hello world:

testlib.c

#include <stdio.h>

void myprint(void);

void myprint()
{
    printf("hello world\n");
}

Sekarang kompilasi sebagai perpustakaan bersama ( perbaikan mac ditemukan di sini ):

$ gcc -shared -Wl,-soname,testlib -o testlib.so -fPIC testlib.c

# or... for Mac OS X 
$ gcc -shared -Wl,-install_name,testlib.so -o testlib.so -fPIC testlib.c

Kemudian, tulis pembungkus menggunakan ctypes:

testlibwrapper.py

import ctypes

testlib = ctypes.CDLL('/full/path/to/testlib.so')
testlib.myprint()

Sekarang jalankan:

$ python testlibwrapper.py

Dan Anda akan melihat hasilnya

Hello world
$

Jika Anda sudah memiliki perpustakaan dalam pikiran, Anda dapat melewati bagian non-python dari tutorial. Pastikan ctypes dapat menemukan pustaka dengan meletakkannya di /usr/libatau direktori standar lainnya. Jika Anda melakukan ini, Anda tidak perlu menentukan lokasi lengkap saat menulis pembungkusnya. Jika Anda memilih untuk tidak melakukan ini, Anda harus memberikan jalur lengkap perpustakaan saat memanggil ctypes.CDLL().

Ini bukan tempat untuk tutorial yang lebih komprehensif, tetapi jika Anda meminta bantuan dengan masalah khusus di situs ini, saya yakin komunitas akan membantu Anda.

PS: Saya berasumsi Anda menggunakan Linux karena Anda pernah menggunakan ctypes.CDLL('libc.so.6'). Jika Anda menggunakan OS lain, banyak hal mungkin berubah sedikit (atau cukup banyak).

Chinmay Kanchi
sumber
1
@ Chinmay: Dapatkah saya memiliki kode yang serupa untuk Windows dan sebagai ganti C, dapatkah Anda memberikan contoh visual c ++? Saya dapat memuat perpustakaan saya tetapi saya tidak dapat mengakses fungsi saya dari file .dll. Itu selalu mengatakan "fungsi 'xyz' tidak ditemukan". Bisakah Anda menyarankan saya cara mengatasi ini? Bersulang.
Neophile
Saya tidak tahu banyak tentang pengembangan Windows, tetapi sepertinya Windows melakukan sesuatu yang aneh, mungkin menggunakan konvensi panggilan yang berbeda? Mungkin Anda mungkin ingin mengekspor fungsi C ++ menggunakan "extern C"?
Chinmay Kanchi
Ya, saya melakukannya tetapi sejauh ini tidak berhasil.
Neophile
6
Terima kasih atas tutorial yang mudah diikuti yang menunjukkan fungsionalitas dasar
ctype
1
cepat dan kotor selalu merupakan tutorial terbaik
lurscher
55

Jawaban oleh Chinmay Kanchi sangat bagus tetapi saya ingin contoh fungsi yang meneruskan dan mengembalikan variabel / array ke kode C ++. Saya pikir saya akan memasukkannya di sini jika itu berguna bagi orang lain.

Meneruskan dan mengembalikan integer

Kode C ++ untuk suatu fungsi yang mengambil integer dan menambahkan satu ke nilai yang dikembalikan,

extern "C" int add_one(int i)
{
    return i+1;
}

Disimpan sebagai berkas test.cpp, perhatikan diperlukan extern "C" (ini dapat dihapus untuk kode C). Ini dikompilasi menggunakan g ++, dengan argumen yang mirip dengan jawaban Chinmay Kanchi,

g++ -shared -o testlib.so -fPIC test.cpp

Kode Python menggunakan load_librarydari numpy.ctypeslibasumsi jalur ke pustaka bersama di direktori yang sama dengan skrip Python,

import numpy.ctypeslib as ctl
import ctypes

libname = 'testlib.so'
libdir = './'
lib=ctl.load_library(libname, libdir)

py_add_one = lib.add_one
py_add_one.argtypes = [ctypes.c_int]
value = 5
results = py_add_one(value)
print(results)

Ini mencetak 6 seperti yang diharapkan.

Melewati dan mencetak larik

Anda juga bisa melewatkan array sebagai berikut, untuk kode C untuk mencetak elemen array,

extern "C" void print_array(double* array, int N)
{
    for (int i=0; i<N; i++) 
        cout << i << " " << array[i] << endl;
}

yang dikompilasi seperti sebelumnya dan diimpor dengan cara yang sama. Kode tambahan Python untuk menggunakan fungsi ini adalah,

import numpy as np

py_print_array = lib.print_array
py_print_array.argtypes = [ctl.ndpointer(np.float64, 
                                         flags='aligned, c_contiguous'), 
                           ctypes.c_int]
A = np.array([1.4,2.6,3.0], dtype=np.float64)
py_print_array(A, 3)

di mana kita menentukan array, argumen pertama ke print_array, sebagai pointer ke array Numpy dari aligned, c_contiguous 64 bit float dan argumen kedua sebagai integer yang memberi tahu kode C jumlah elemen dalam array Numpy. Ini kemudian dicetak dengan kode C sebagai berikut,

1.4
2.6
3.0
Ed Smith
sumber
5
Ini adalah jawaban tambahan yang bagus - sayang sekali tidak ada dua jawaban yang dicentang :(
jtlz2
Tidak yakin apakah terlalu jelas, tetapi ada kesalahan pada kode. Itu hilang import numpy as np. Jika tidak, ia tidak dapat menemukan np.float64dan barang-barang lainnya.
Ben
@ Ben, tempat yang bagus, menambahkannya di
Ed Smith
11

Pertama: >>>Kode yang Anda lihat dalam contoh python adalah cara untuk menunjukkan bahwa itu adalah kode Python. Ini digunakan untuk memisahkan kode Python dari keluaran. Seperti ini:

>>> 4+5
9

Di sini kita melihat bahwa baris yang dimulai dengan >>>adalah kode Python, dan 9 adalah hasilnya. Ini persis seperti yang terlihat jika Anda memulai penerjemah Python, itulah mengapa dilakukan seperti itu.

Anda tidak pernah memasukkan >>>bagian tersebut ke dalam .pyfile.

Itu menangani kesalahan sintaks Anda.

Kedua, ctypes hanyalah salah satu dari beberapa cara membungkus pustaka Python. Cara lain adalah SWIG , yang akan melihat pustaka Python Anda dan menghasilkan modul ekstensi Python C yang mengekspos C API. Cara lain adalah dengan menggunakan Cython .

Semuanya memiliki kelebihan dan kekurangan.

SWIG hanya akan mengekspos C API Anda ke Python. Itu berarti Anda tidak mendapatkan objek atau apa pun, Anda harus membuat file Python terpisah melakukan itu. Bagaimanapun juga umum untuk memiliki modul yang disebut say "wowza" dan modul SWIG yang disebut "_wowza" yang merupakan pembungkus di sekitar C API. Ini adalah cara yang bagus dan mudah untuk melakukan sesuatu.

Cython menghasilkan file Ekstensi-C. Keuntungannya adalah semua kode Python yang Anda tulis dibuat menjadi C, jadi objek yang Anda tulis juga dalam C, yang dapat menjadi peningkatan performa. Tapi Anda harus belajar bagaimana itu berinteraksi dengan C jadi itu sedikit pekerjaan ekstra untuk mempelajari bagaimana menggunakannya.

ctypes memiliki keuntungan bahwa tidak ada kode-C untuk dikompilasi, jadi sangat bagus digunakan untuk membungkus pustaka standar yang ditulis oleh orang lain, dan sudah ada dalam versi biner untuk Windows dan OS X.

Lennart Regebro
sumber