tutorial pyx compile python c cython

python - pyx - cython tutorial



Llama al código python desde c vía cython. (2)

Si cambia el nombre de quacker.pyx a quacker.py , todo es realmente correcto. El único problema es que su programa no buscará módulos de python en el directorio actual, lo que dará como resultado la salida:

Exception NameError: "name ''quack'' is not defined" in ''caller.call_quack'' ignored

Sin embargo, si agrega el directorio actual a la variable de entorno PYTHONPATH, la salida se convierte en la que esperaría:

$ PYTHONPATH=".:$PYTHONPATH" ./main Quack!

Cuando se ejecuta el shell de Python, de acuerdo con la documentation el directorio actual (o el directorio que contiene el script) se agrega a la variable sys.path automáticamente, pero al crear un programa simple utilizando Py_Initialize y Py_Finalize esto no parece suceder. Dado que la variable PYTHONPATH también se usa para poblar la variable sys.path python, la solución anterior produce el resultado correcto.

Alternativamente, debajo de la línea Py_Intialize , puede agregar una cadena vacía a sys.path siguiente manera simplemente ejecutando un código de Python, especificado como una cadena:

PyRun_SimpleString("import sys/nsys.path.insert(0,'''')");

Después de recompilar, simplemente ejecutar ./main debería funcionar.

Editar

Es realmente interesante ver qué sucede si ejecuta el código como se especifica en la pregunta, así que sin cambiar el nombre del archivo quacker.pyx . En ese caso, la función initcaller() intenta importar el módulo quacker , pero como no existe quacker.py o quacker.pyc , no se puede encontrar el módulo y la función initcaller() produce un error.

Ahora, este error se informa de la manera de python, al generar una excepción. Pero el código en el archivo main.c no lo comprueba. No soy un experto en esto, pero en mis pruebas, agregar el siguiente código debajo de initcaller() pareció funcionar:

if (PyErr_Occurred()) { PyErr_Print(); return -1; }

La salida del programa se convierte en la siguiente:

Traceback (most recent call last): File "caller.pyx", line 1, in init caller (caller.c:836) from quacker import quack ImportError: No module named quacker

Al llamar a la función initquacker() antes de initcaller() , el nombre del módulo quacker ya se registra, por lo que la llamada de importación que se realiza dentro de initcaller() detectará que ya está cargada y la llamada se realizará correctamente.

Así que me gustaría llamar a algún código python desde c a través de cython. He conseguido llamar al código cython desde c. Y también puedo llamar al código python desde cython. Pero cuando lo agrego todo, faltan algunas cosas.

Aquí está mi código de python ( quacker.pyx ):

def quack(): print "Quack!"

Aquí está mi "puente" de caller.pyx ( caller.pyx ):

from quacker import quack cdef public void call_quack(): quack()

Y aquí está el código c ( main.c ):

#include <Python.h> #include "caller.h" int main() { Py_Initialize(); initcaller(); call_quack(); Py_Finalize(); return 0; }

Cuando ejecuto esto obtengo esta excepción:

Exception NameError: "name ''quack'' is not defined" in ''caller.call_quack'' ignored

Las piezas faltantes que estoy sospechando:

  • No he llamado a initquacker()
  • No he incluido quacker.h
  • Cython no produjo ningún quacker.h - only quacker.c
  • caller.c no importa quacker.h ni llama a initquacker()

No estoy realmente seguro de que sea posible hacer lo que estoy tratando de hacer, pero me parece que debería ser así. Me encantaría escuchar cualquier entrada que pueda tener.

Editar:

Así es como cythonize / compile / link / run:

$ cython *.pyx $ cc -c *.c -I/System/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7 $ cc -L/System/Library/Frameworks/Python.framework/Versions/2.7/lib -L/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/config -lpython2.7 -ldl *.o -o main $ ./main


Tal vez esto no es lo que quieres pero lo puse funcionando por los siguientes cambios:

en quacker.pyx he añadido

cdef public int i

Para forzar a Cython a generar el archivo .h .

Y luego en lo principal:

#include <Python.h> #include "caller.h" #include "quacker.h" int main() { Py_Initialize(); initquacker(); initcaller(); call_quack(); Py_Finalize(); return 0; }