J'ai pour tâche de "wrapper" une bibliothèque ac dans une classe python. Les documents sont incroyablement vagues à ce sujet. Il semble qu'ils ne s'attendent qu'à des fonctions avancées python utilisateurs Bien, je suis débutant en python et ai besoin d’aide.
Une aide étape par étape serait formidable.
J'ai donc ma bibliothèque c. Que fais-je? Quels fichiers dois-je mettre où? Comment importer la bibliothèque? J'ai lu qu'il pourrait y avoir un moyen de "boucler automatiquement" en Python?
(Au fait, j’ai fait le tutoriel ctypes sur python.net et cela ne marche pas. C’est-à-dire que je pense qu’ils supposent que je devrais être capable de compléter le reste des étapes.
En fait, c'est l'erreur que j'obtiens avec leur code:
File "importtest.py", line 1
>>> from ctypes import *
SyntaxError: invalid syntax
Je pourrais vraiment utiliser une aide étape par étape à ce sujet! Merci ~
Voici un tutoriel rapide et sale sur les ctypes.
Commencez par écrire votre bibliothèque C. Voici un exemple simple de bonjour:
#include <stdio.h>
void myprint(void);
void myprint()
{
printf("hello world\n");
}
Maintenant, compilez-le en tant que bibliothèque partagée ( correctif mac trouvé ici ):
$ 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
Ensuite, écrivez un wrapper en utilisant ctypes:
import ctypes
testlib = ctypes.CDLL('/full/path/to/testlib.so')
testlib.myprint()
Maintenant exécutez-le:
$ python testlibwrapper.py
Et vous devriez voir la sortie
Hello world
$
Si vous avez déjà une bibliothèque en tête, vous pouvez ignorer la partie non python du didacticiel. Assurez-vous que les types de fichiers peuvent trouver la bibliothèque en la plaçant dans /usr/lib
Ou dans un autre répertoire standard. Si vous procédez ainsi, vous n'avez pas besoin de spécifier le chemin complet lors de l'écriture du wrapper. Si vous choisissez de ne pas le faire, vous devez fournir le chemin complet de la bibliothèque lorsque vous appelez ctypes.CDLL()
.
Ce n'est pas l'endroit idéal pour un tutoriel plus complet, mais si vous demandez de l'aide pour des problèmes spécifiques sur ce site, je suis sûr que la communauté vous aiderait.
PS: Je suppose que vous êtes sous Linux parce que vous avez utilisé ctypes.CDLL('libc.so.6')
. Si vous utilisez un autre système d'exploitation, les choses pourraient changer un peu (ou beaucoup).
La réponse de Chinmay Kanchi est excellente, mais je voulais un exemple de fonction qui passe et renvoie des variables/tableaux à un code C++. Je pensais l'inclure ici au cas où cela serait utile à d'autres.
Passer et renvoyer un entier
Le code C++ pour une fonction qui prend un entier et en ajoute un à la valeur renvoyée,
extern "C" int add_one(int i)
{
return i+1;
}
Enregistré en tant que fichier test.cpp
, notez le obligatoire extern "C" (vous pouvez le supprimer pour le code C). Ceci est compilé en utilisant g ++, avec des arguments similaires à ceux de Chinmay Kanchi,
g++ -shared -o testlib.so -fPIC test.cpp
Le code Python utilise load_library
du numpy.ctypeslib
en supposant que le chemin de la bibliothèque partagée se trouve dans le même répertoire que le script 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)
Ceci affiche 6 comme prévu.
Passer et imprimer un tableau
Vous pouvez également passer des tableaux comme suit, pour qu’un code C imprime l’élément d’un tableau,
extern "C" void print_array(double* array, int N)
{
for (int i=0; i<N; i++)
cout << i << " " << array[i] << endl;
}
qui est compilé comme avant et importé de la même manière. Le code supplémentaire Python pour utiliser cette fonction serait alors,
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)
où nous spécifions le tableau, le premier argument de print_array
, en tant que pointeur sur un tableau Numpy de 64 bits flottants alignés, c_contiguous et le deuxième argument sous la forme d'un entier indiquant au code C le nombre d'éléments contenus dans le tableau Numpy. Ceci a ensuite imprimé par le code C comme suit,
1.4
2.6
3.0
Premièrement: le >>>
Le code que vous voyez dans python est un moyen d'indiquer qu'il s'agit d'un code Python. Il est utilisé pour séparer Python = code de la sortie, comme ceci:
>>> 4+5
9
Nous voyons ici que la ligne qui commence par >>>
est le code Python, et le résultat obtenu est 9. C’est exactement à quoi il ressemble si vous démarrez un interpréteur Python, raison pour laquelle il fait comme ça.
Vous n'entrez jamais le >>>
partie dans un .py
fichier
Cela prend en charge votre erreur de syntaxe.
Deuxièmement, ctypes n’est qu’un des nombreux moyens d’emballer Python. Les autres moyens sont SWIG , qui examinera votre Python bibliothèque et générez un module d'extension Python C qui expose l'API C.). Une autre façon consiste à utiliser Cython .
Ils ont tous des avantages et des inconvénients.
SWIG exposera uniquement votre API C à Python. Cela signifie que vous n’obtenez aucun objet ni rien, vous devrez créer un fichier distinct Python). Il est cependant courant d’avoir un module appelé "wowza" et un fichier SWIG. Le module appelé "_wowza" est l’encapsuleur de l’API C. C’est un moyen simple et agréable de faire les choses.
Cython génère un fichier C-Extension. L’avantage est que tout le code Python que vous écrivez est transformé en C, de sorte que les objets que vous écrivez sont également en C, ce qui peut représenter une amélioration des performances. Mais vous devrez apprendre comment il s’interface avec C, c’est donc un peu plus de travail d’apprendre à l’utiliser.
les ctypes ont l'avantage de ne pas compiler de code C, il est donc très agréable d'utiliser des bibliothèques standard écrites par quelqu'un d'autre et qui existent déjà dans les versions binaires pour Windows et OS X.