web-dev-qa-db-fra.com

Appel des fonctions C dans Python

J'ai un tas de fonctions que j'ai écrites en C et j'aimerais avoir du code que j'ai écrit en Python pour pouvoir accéder à ces fonctions.

J'ai lu plusieurs questions ici qui traitent d'un problème similaire ( ici et ici par exemple) mais je ne sais pas quelle approche je dois adopter.

Une question recommande les ctypes et une autre recommande le cython. J'ai lu un peu de la documentation pour les deux, et je ne sais pas trop lequel fonctionnera le mieux pour moi.

Fondamentalement, j'ai écrit du code python pour faire des FFT bidimensionnelles et j'aimerais que le code C puisse voir ce résultat et ensuite le traiter à travers les différentes fonctions C que j'ai Je ne sais pas s'il sera plus facile pour moi d'appeler le Python de C ou vice versa.

30
Kitchi

Si je comprends bien, vous n'avez aucune préférence pour le dialogue comme c => python ou comme python => c. Dans ce cas, je recommanderais Cython. Il est assez ouvert à de nombreux types de manipulation, spécialement, dans votre cas, appelant une fonction qui a été écrite en Python de C.

Voici comment cela fonctionne ( public api ):

L'exemple suivant suppose que vous avez une classe Python (self en est une instance) et que cette classe a une méthode (nom method) que vous veulent appeler cette classe et traiter le résultat (ici, un double) de C. Cette fonction, écrite dans un Cython extension vous aiderait à faire cet appel.

cdef public api double cy_call_func_double(object self, char* method, bint *error):
    if (hasattr(self, method)):
        error[0] = 0
        return getattr(self, method)();
    else:
        error[0] = 1

Côté C, vous pourrez alors effectuer l'appel comme suit:

PyObject *py_obj = ....
...
if (py_obj) {
    int error;
    double result;
    result = cy_call_func_double(py_obj, (char*)"initSimulation", &error);
    cout << "Do something with the result : " << result << endl;
}

PyObject est un struct fourni par l'API Python/C Après avoir intercepté le py_obj (en lançant un python object, dans votre extension cython comme ceci: <PyObject *>my_python_object), vous pourrez enfin appeler la méthode initSimulation dessus et faire quelque chose avec le résultat. (Ici un double, mais Cython peut facilement gérer vectors, sets, ... )

Eh bien, je suis conscient que ce que je viens d'écrire peut être déroutant si vous n'avez jamais rien écrit en utilisant Cython, mais il vise à être une courte démonstration des nombreuses choses qu'il peut faire pour vous en termes de fusion .

D'un autre côté, cette approche peut prendre plus de temps que recoder votre code Python en C, selon la complexité de vos algorithmes. À mon avis, investir du temps dans l'apprentissage de Cython n'est pertinent que si vous prévoyez d'avoir ce genre de besoins assez souvent ...

J'espère que c'était au moins informatif ...

10
Gauthier Boaglio

Vous devez appeler C depuis Python en écrivant un wrapper ctypes . Cython permet d'accélérer l'exécution de code de type python, ctypes sert à rendre les fonctions C appelables à partir de python. Ce que vous devez faire est le suivant:

  1. Écrivez les fonctions C que vous souhaitez utiliser. (Vous l'avez probablement déjà fait)
  2. Créez un objet partagé (.so, pour linux, os x, etc.) ou une bibliothèque chargée dynamiquement (.dll, pour windows) pour ces fonctions. (Peut-être que vous l'avez déjà fait aussi)
  3. Écrivez l'encapsuleur ctypes (C'est plus facile qu'il n'y paraît, j'ai écrit un tutoriel pour cela )
  4. Appelez une fonction à partir de ce wrapper en Python. (C'est aussi simple que d'appeler n'importe quelle autre fonction python)
55
Florian Rhiem

Eh bien, ici, vous faites référence à deux choses ci-dessous.

  1. Comment appeler la fonction c à partir de python (Extension de python)
  2. Comment appeler python à partir du programme C (intégration de Python)

Pour # 2, c'est 'Embedding Python'

Vous pouvez utiliser le segment de code ci-dessous:

#include "python.h"

int main(int argc, char *argv[]) {   
Py_SetProgramName(argv[0]);  /* optional but recommended */   
Py_Initialize();   
PyRun_SimpleString("from time import time,ctime\n"
    "print 'Today is',ctime(time())\n");
/*Or if you want to run python file within from the C code*/       
//pyRun_SimpleFile("Filename");    
Py_Finalize();   
return 0; }

Pour # 1 c'est-à-dire 'Extension Python' Alors le meilleur pari serait d'utiliser des Ctypes (btw portable sur toutes les variantes) de python).

de l'importation de ctypes *

libc = cdll.msvcrt

imprimer libc.time (Aucun)

1438069008

printf = libc.printf

printf ("Bonjour,% s\n", "Monde!")

Bonjour le monde! 14

printf ("% d bouteilles de bière\n", 42)

42 bouteilles de bière 19

Pour un guide détaillé, vous pouvez vous référer à mon article de blog :

4
Jadav Bheda

Il sera plus facile d'appeler C depuis python. Votre scénario semble étrange - normalement, les gens écrivent la plupart du code en python sauf pour la partie gourmande en processeur, qui est écrite en C. La FFT bidimensionnelle est-elle la partie gourmande en calcul de votre code?

2
xuanji