ctypes - Новачок


100

У мене є завдання "перемотати" бібліотеку змінного струму в клас python. Документи з цього питання неймовірно розпливчасті. Здається, вони очікують, що лише просунуті користувачі python реалізуватимуть типи. Ну я початківець в пітоні і мені потрібна допомога.

Якась покрокова допомога була б чудовою.

Тож у мене є моя бібліотека c. Що мені робити? Які файли куди класти? Як імпортувати бібліотеку? Я читав, що може бути спосіб "автоматичного загортання" на Python?

(До речі, я зробив підручник з типами на python.net, і він не працює. Значить, я думаю, що вони припускають, що я маю змогу заповнити решту кроків.

Насправді це помилка, яку я отримую з їх кодом:

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

Я дійсно міг би скористатися деякою покроковою допомогою щодо цього! Спасибі ~


10
У вас є >>> importport.py? Коли люди розміщують код >>> у кожному рядку, це означає, що він працює в інтерактивній оболонці. Щоб запустити його з файлу, видаліть >>> (це 3> знаки та пробіл), де б він не з’явився.
Chinmay Kanchi

4
Не вводите >>>s. Вони надруковані інтерактивною оболонкою і не повинні залишатися у вихідному файлі.
nmichaels

8
>>>у файлі .py! ТАКОЖ! Ніколи цього не бачив!
Девід Геффернан

3
Чесно кажучи, вивчіть трохи Python (принаймні трохи), перш ніж почати возитися з ctypes. Ви ніколи не знайдете підручник з типами, який передбачає, що ви не знаєте базового Python.
Чінмай Канчі

3
@spentak: якщо ви звертаєтесь за допомогою, надайте адекватну інформацію. Принаймні, покажіть нам останню версію коду, про яку ви говорите. Що, наприклад, на "рядку 3"?
Франческо

Відповіді:


228

Ось швидкий і брудний підручник з типами.

Спочатку напишіть свою бібліотеку С. Ось простий приклад світу привіт:

testlib.c

#include <stdio.h>

void myprint(void);

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

Тепер скомпілюйте його як спільну бібліотеку ( тут виправлено mac ):

$ 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

Потім напишіть обгортку за допомогою ctypes:

testlibwrapper.py

import ctypes

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

Тепер виконайте це:

$ python testlibwrapper.py

І ви повинні побачити вихід

Hello world
$

Якщо у вас уже є бібліотека, ви можете пропустити непітонну частину підручника. Переконайтесь, що типи можуть знайти бібліотеку, помістивши її в /usr/libінший стандартний каталог. Якщо ви це зробите, вам не потрібно вказувати повний шлях під час написання обгортки. Якщо ви вирішите не робити цього, під час дзвінка ви повинні вказати повний шлях бібліотеки ctypes.CDLL().

Це не місце для більш повного навчального посібника, але якщо ви попросите допомоги щодо конкретних проблем на цьому веб-сайті, я впевнений, що громада допоможе вам допомогти.

PS: Я припускаю, що ви в Linux, тому що ви використовували ctypes.CDLL('libc.so.6'). Якщо ви перебуваєте в іншій ОС, все може трохи змінитися (або досить сильно).


1
@ Chinmay: Чи можу я мати подібний код для Windows, а замість C, чи можете ви надати наочний приклад c ++? Я можу завантажити свою бібліотеку, але я не в змозі отримати доступ до своїх функцій з файлу .dll. Тут завжди написано "функцію 'xyz' не знайдено". Не могли б ви запропонувати мені спосіб подолати це? Ура.
Неофіл

Я не дуже багато знаю про розробку Windows, але схоже, що Windows робить щось химерне, можливо, воно використовує інший режим викликів? Можливо, ви можете шукати, як експортувати свої функції C ++, використовуючи "extern C"?
Chinmay Kanchi

Так, я це зробив, але поки що не пощастило.
Неофіл

6
Дякуємо за простий у виконанні підручник, який показує основну функціональність ctype
okysabeni

1
швидкий і брудний завжди найкращі підручники
lurscher

55

Відповідь Чінмай Канчі відмінна, але я хотів приклад функції, яка передає та повертає змінні / масиви в код C ++. Я хоч би включив його сюди на випадок, якщо він корисний іншим.

Проходження та повернення цілого числа

Код C ++ для функції, яка приймає ціле число і додає його до повернутого значення,

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

Збережено як файл test.cpp, зверніть увагу на необхідний зовнішній "C" (його можна видалити для коду C). Це складено за допомогою g ++, з аргументами, подібними до відповіді Чінмай Канчі,

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

Код Python використовує load_libraryз numpy.ctypeslibприпущення шлях до спільної бібліотеки в тому ж каталозі, що і сценарій 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)

Це друкує 6, як очікувалося.

Передача та друк масиву

Ви також можете передавати масиви наступним чином, щоб код C надрукував елемент масиву,

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

який складається, як раніше, та імпортується таким же чином. Додатковим кодом Python для використання цієї функції буде,

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)

де ми print_arrayзадаємо масив, перший аргумент на , як вказівник на Numpy масив вирівняних, c_contiguous 64-бітових плаває, а другий аргумент як ціле число, яке повідомляє коду C кількість елементів масиву Numpy. Потім він друкується кодом С наступним чином,

1.4
2.6
3.0

5
Це чудова додаткова відповідь - ганьба не може бути двох
відзначених

Не впевнений, чи це занадто очевидно, але в коді є помилка. Він відсутній import numpy as np. Інакше не вдається знайти np.float64і інші речі.
Бен,

@Ben, хороше місце, додав це у
Ед Сміт

11

По-перше: >>>код, який ви бачите в прикладах python, - це спосіб вказати, що це код Python. Він використовується для відділення коду Python від виводу. Подобається це:

>>> 4+5
9

Тут ми бачимо, що рядок, з якої починається, >>>- це код Python, і 9 - це те, до чого він призводить. Це саме те, як це виглядає, якщо ви запускаєте інтерпретатор Python, тому це робиться так.

Ви ніколи не вводите >>>частину у .pyфайл.

Це допоможе уникнути вашої синтаксичної помилки.

По-друге, ctypes - це лише один із кількох способів обгортання бібліотек Python. Іншими способами є SWIG , який розглядає вашу бібліотеку Python і генерує модуль розширення Python C, який відкриває API C. Ще один спосіб - використовувати Cython .

Усі вони мають переваги та недоліки.

SWIG відкриє ваш C API тільки Python. Це означає, що ви не отримуєте жодних об’єктів чи нічого, вам доведеться зробити окремий файл Python, роблячи це. Однак, як правило, є модуль під назвою "wowza" і модуль SWIG під назвою "_wowza", який є обгорткою навколо API C. Це приємний і простий спосіб робити речі.

Cython створює файл з розширенням C. Користь полягає в тому, що весь написаний вами код Python перетворюється на C, тому об'єкти, які ви пишете, також знаходяться в C, що може бути покращенням продуктивності. Але вам доведеться дізнатися, як він взаємодіє з C, так що це трохи додаткова робота, щоб навчитися ним користуватися.

Перевага ctypes полягає в тому, що для компіляції немає C-коду, тому дуже приємно використовувати його для обтікання стандартних бібліотек, написаних кимось іншим, і вже існує у двійкових версіях для Windows та OS X.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.