Extendiendo python - a swig, no a swig o Cython


Encontré el cuello de botella en mi código python, jugué con psycho, etc. Luego decidió escribir una extensión c / c++ para el rendimiento.

Con la ayuda de swig, casi no necesita preocuparse por los argumentos, etc. Todo funciona bien.

Ahora mi pregunta: swig crea un archivo py bastante grande que hace muchas 'checkings' y 'PySwigObject' antes de llamar al real .pyd or. so código.

¿Alguien de ustedes tiene alguna experiencia si hay algo más de rendimiento para gana si escribes a mano este archivo o dejas que swig lo haga.

Author: JBentley, 2009-01-19

9 answers

Seguro que siempre tendrá una ganancia de rendimiento haciendo esto a mano, pero la ganancia será muy pequeña en comparación con el esfuerzo requerido para hacer esto. No tengo ninguna cifra para darle, pero no recomiendo esto, porque tendrá que mantener la interfaz a mano, y esto no es una opción si su módulo es grande!

Hizo lo correcto al elegir usar un lenguaje de scripting porque quería un desarrollo rápido. De esta manera has evitado el síndrome de optimización temprana, y ahora desea optimizar las piezas de cuello de botella, ¡genial! Pero si haces la interfaz C / python a mano caerás en el síndrome de optimización temprana con seguridad.

Si quieres algo con menos código de interfaz, puedes pensar en crear una dll a partir de tu código C, y usar esa biblioteca directamente desde python con cstruct.

Considere también Cython si desea utilizar solo código python en su programa.

 25
Author: Mapad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-24 16:26:10

Deberías considerar Boost.Python si no está planeando generar enlaces para otros lenguajes también con swig.

Si tienes muchas funciones y clases para enlazar, Py++ es una gran herramienta que genera automáticamente el código necesario para hacer los enlaces.

Pybindgen también puede ser una opción, pero es un proyecto nuevo y menos completo que Boost.Python.


Editar:

Tal vez necesito ser más explícito sobre pro y desventaja.

  • Swig:

    Pro: puede generar enlaces para muchos lenguajes de scripting.

    Contras: No me gusta la forma en que funciona el analizador. No se si el hizo algún progreso, pero hace dos años el analizador de C++ era bastante limitado. La mayor parte del tiempo tuve que copiar / más allá de mi .los encabezados h añaden algunos caracteres % y dan pistas adicionales al analizador de swig.

    También tuve que lidiar con la C-API de Python de vez en cuando para (no tan) complicadas conversiones de tipos.

    Ya no lo uso.

  • Aumentar.Python:

    Pro: Es una biblioteca muy completa. Le permite hacer casi todo lo que es posible con la C-API, pero en C++. Nunca tuve que escribir código C-API con esta biblioteca. También nunca encontré un error debido a la biblioteca. El código para los enlaces funciona como un charm o un refuse compile.

    Es probablemente una de las mejores soluciones disponibles actualmente si ya tiene alguna biblioteca de C++ para enlazar. Pero si solo tiene una pequeña función de C para reescribir, probablemente intentaría con Cython.

    Contras: si no tienes un Boost pre-compilado.Biblioteca Python vas a usar Bjam (una especie de reemplazo de make). Realmente odio Bjam y su sintaxis.

    Las bibliotecas de Python creadas con B. P tienden a volverse obesas. También toma un lote de tiempo compilarlos.

  • Py++ (descontinuado): es Boost.Python hecho fácil. Py++ utiliza un analizador de C++ para leer el código y luego genera Impulsar.Código Python automáticamente. También tiene un gran apoyo de su autor (no, no soy yo; -)).

    Contras: solo los problemas debidos a Boost.Python mismo. Actualización: A partir de 2014 este proyecto ahora parece descontinuado.

  • Pybindgen:

    Genera el código que trata con la C-API. Puede describir funciones y clases en un archivo Python, o dejar que Pybindgen lea sus encabezados y genere enlaces automáticamente (para esto utiliza pygccxml, una biblioteca de python escrita por el autor de Py++).

    Contras: es un proyecto joven, con un equipo más pequeño que Boost.Python. Todavía hay algunas limitaciones: no puede usar herencia múltiple para sus clases de C++, devoluciones de llamada (no automáticamente, sin embargo, se puede escribir código de manejo de devolución de llamada personalizado). Traducción de las excepciones de Python a C.

    Definitivamente vale la pena echarle un buen vistazo.

  • Una nueva: El 20/01/2009 el autor de Py++ anunció un nuevo paquete para interconectar código C / C++ con python. Se basa en ctypes. No lo he intentado ya, pero lo haré! Nota: este proyecto parece descontinuado, como Py++.

  • CFFI : No sabía la existencia de éste hasta hace muy poco, así que por ahora no puedo dar mi opinión. Parece que puede definir funciones C en cadenas de Python y llamarlas directamente desde el mismo módulo de Python.

  • Cython : Este es el método que estoy usando actualmente en mis proyectos. Básicamente escribes código en especial .pyx archivos. Esos archivos se compilan (traducen) en código C que a su vez se compilan en módulos CPython. El código Cython puede parecerse a Python normal (y de hecho Python puro es válido .archivos pyx Cython), pero también puede obtener más información como tipos de variables. Este tipo opcional permite a Cython generar código C más rápido. El código en los archivos de Cython puede llamar tanto a funciones puras de Python como a funciones de C y C++ (y también a métodos de C++).

    Me tomó algún tiempo pensar en Cython, que en el mismo código llame a la función C y C++, mezcle las variables Python y C, y así sucesivamente. Pero es un lenguaje muy poderoso, con una comunidad activa (en 2014) y amigable.

 58
Author: ascobol,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-07 22:33:31

SWIG 2.0.4 ha introducido una nueva opción incorporada que mejora el rendimiento. Hice algunos benchmarking usando un programa de ejemplo que hace un montón de llamadas rápidas a una extensión de C++. Construí la extensión usando boost.python, PyBindGen, SIP y SWIG con y sin la opción-builtin. Aquí están los resultados (promedio de 100 carreras):

SWIG with -builtin     2.67s
SIP                    2.70s
PyBindGen              2.74s
boost.python           3.07s
SWIG without -builtin  4.65s

SWIG solía ser más lento. Con la opción new-builtin, SWIG parece ser el más rápido.

 27
Author: user763305,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-14 10:21:51

Usar Cython es bastante bueno. Puede escribir su extensión C con una sintaxis similar a Python y hacer que genere código C. Boilerplate incluido. Dado que ya tiene el código en python, tiene que hacer solo unos pocos cambios en su código de cuello de botella y el código C se generará a partir de él.

Ejemplo. hello.pyx:

cdef int hello(int a, int b):
    return a + b

Que genera 601 líneas de código repetitivo:

/* Generated by Cython 0.10.3 on Mon Jan 19 08:24:44 2009 */

#define PY_SSIZE_T_CLEAN
#include "Python.h"
#include "structmember.h"
#ifndef PY_LONG_LONG
  #define PY_LONG_LONG LONG_LONG
#endif
#ifndef DL_EXPORT
  #define DL_EXPORT(t) t
#endif
#if PY_VERSION_HEX < 0x02040000
  #define METH_COEXIST 0
#endif
#if PY_VERSION_HEX < 0x02050000
  typedef int Py_ssize_t;
  #define PY_SSIZE_T_MAX INT_MAX
  #define PY_SSIZE_T_MIN INT_MIN
  #define PyInt_FromSsize_t(z) PyInt_FromLong(z)
  #define PyInt_AsSsize_t(o)   PyInt_AsLong(o)
  #define PyNumber_Index(o)    PyNumber_Int(o)
  #define PyIndex_Check(o)     PyNumber_Check(o)
#endif
#if PY_VERSION_HEX < 0x02060000
  #define Py_REFCNT(ob) (((PyObject*)(ob))->ob_refcnt)
  #define Py_TYPE(ob)   (((PyObject*)(ob))->ob_type)
  #define Py_SIZE(ob)   (((PyVarObject*)(ob))->ob_size)
  #define PyVarObject_HEAD_INIT(type, size) \
          PyObject_HEAD_INIT(type) size,
  #define PyType_Modified(t)

  typedef struct {
       void *buf;
       PyObject *obj;
       Py_ssize_t len;
       Py_ssize_t itemsize;
       int readonly;
       int ndim;
       char *format;
       Py_ssize_t *shape;
       Py_ssize_t *strides;
       Py_ssize_t *suboffsets;
       void *internal;
  } Py_buffer;

  #define PyBUF_SIMPLE 0
  #define PyBUF_WRITABLE 0x0001
  #define PyBUF_LOCK 0x0002
  #define PyBUF_FORMAT 0x0004
  #define PyBUF_ND 0x0008
  #define PyBUF_STRIDES (0x0010 | PyBUF_ND)
  #define PyBUF_C_CONTIGUOUS (0x0020 | PyBUF_STRIDES)
  #define PyBUF_F_CONTIGUOUS (0x0040 | PyBUF_STRIDES)
  #define PyBUF_ANY_CONTIGUOUS (0x0080 | PyBUF_STRIDES)
  #define PyBUF_INDIRECT (0x0100 | PyBUF_STRIDES)

#endif
#if PY_MAJOR_VERSION < 3
  #define __Pyx_BUILTIN_MODULE_NAME "__builtin__"
#else
  #define __Pyx_BUILTIN_MODULE_NAME "builtins"
#endif
#if PY_MAJOR_VERSION >= 3
  #define Py_TPFLAGS_CHECKTYPES 0
  #define Py_TPFLAGS_HAVE_INDEX 0
#endif
#if (PY_VERSION_HEX < 0x02060000) || (PY_MAJOR_VERSION >= 3)
  #define Py_TPFLAGS_HAVE_NEWBUFFER 0
#endif
#if PY_MAJOR_VERSION >= 3
  #define PyBaseString_Type            PyUnicode_Type
  #define PyString_Type                PyBytes_Type
  #define PyInt_Type                   PyLong_Type
  #define PyInt_Check(op)              PyLong_Check(op)
  #define PyInt_CheckExact(op)         PyLong_CheckExact(op)
  #define PyInt_FromString             PyLong_FromString
  #define PyInt_FromUnicode            PyLong_FromUnicode
  #define PyInt_FromLong               PyLong_FromLong
  #define PyInt_FromSize_t             PyLong_FromSize_t
  #define PyInt_FromSsize_t            PyLong_FromSsize_t
  #define PyInt_AsLong                 PyLong_AsLong
  #define PyInt_AS_LONG                PyLong_AS_LONG
  #define PyInt_AsSsize_t              PyLong_AsSsize_t
  #define PyInt_AsUnsignedLongMask     PyLong_AsUnsignedLongMask
  #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask
  #define __Pyx_PyNumber_Divide(x,y)         PyNumber_TrueDivide(x,y)
#else
  #define __Pyx_PyNumber_Divide(x,y)         PyNumber_Divide(x,y)
  #define PyBytes_Type                 PyString_Type
#endif
#if PY_MAJOR_VERSION >= 3
  #define PyMethod_New(func, self, klass) PyInstanceMethod_New(func)
#endif
#if !defined(WIN32) && !defined(MS_WINDOWS)
  #ifndef __stdcall
    #define __stdcall
  #endif
  #ifndef __cdecl
    #define __cdecl
  #endif
#else
  #define _USE_MATH_DEFINES
#endif
#ifdef __cplusplus
#define __PYX_EXTERN_C extern "C"
#else
#define __PYX_EXTERN_C extern
#endif
#include <math.h>
#define __PYX_HAVE_API__helloworld

#ifdef __GNUC__
#define INLINE __inline__
#elif _WIN32
#define INLINE __inline
#else
#define INLINE 
#endif

typedef struct 
    {PyObject **p; char *s; long n; 
     char is_unicode; char intern; char is_identifier;} 
     __Pyx_StringTabEntry; /*proto*/

static int __pyx_skip_dispatch = 0;


/* Type Conversion Predeclarations */

#if PY_MAJOR_VERSION < 3
#define __Pyx_PyBytes_FromString PyString_FromString
#define __Pyx_PyBytes_AsString   PyString_AsString
#else
#define __Pyx_PyBytes_FromString PyBytes_FromString
#define __Pyx_PyBytes_AsString   PyBytes_AsString
#endif

#define __Pyx_PyBool_FromLong(b) ((b) ? (Py_INCREF(Py_True), Py_True) : (Py_INCREF(Py_False), Py_False))
static INLINE int __Pyx_PyObject_IsTrue(PyObject* x);
static INLINE PY_LONG_LONG __pyx_PyInt_AsLongLong(PyObject* x);
static INLINE unsigned PY_LONG_LONG __pyx_PyInt_AsUnsignedLongLong(PyObject* x);
static INLINE Py_ssize_t __pyx_PyIndex_AsSsize_t(PyObject* b);

#define __pyx_PyInt_AsLong(x) (PyInt_CheckExact(x) ? PyInt_AS_LONG(x) : PyInt_AsLong(x))
#define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x))

static INLINE unsigned char __pyx_PyInt_unsigned_char(PyObject* x);
static INLINE unsigned short __pyx_PyInt_unsigned_short(PyObject* x);
static INLINE char __pyx_PyInt_char(PyObject* x);
static INLINE short __pyx_PyInt_short(PyObject* x);
static INLINE int __pyx_PyInt_int(PyObject* x);
static INLINE long __pyx_PyInt_long(PyObject* x);
static INLINE signed char __pyx_PyInt_signed_char(PyObject* x);
static INLINE signed short __pyx_PyInt_signed_short(PyObject* x);
static INLINE signed int __pyx_PyInt_signed_int(PyObject* x);
static INLINE signed long __pyx_PyInt_signed_long(PyObject* x);
static INLINE long double __pyx_PyInt_long_double(PyObject* x);
#ifdef __GNUC__
/* Test for GCC > 2.95 */
#if __GNUC__ > 2 ||               (__GNUC__ == 2 && (__GNUC_MINOR__ > 95)) 
#define likely(x)   __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#else /* __GNUC__ > 2 ... */
#define likely(x)   (x)
#define unlikely(x) (x)
#endif /* __GNUC__ > 2 ... */
#else /* __GNUC__ */
#define likely(x)   (x)
#define unlikely(x) (x)
#endif /* __GNUC__ */

static PyObject *__pyx_m;
static PyObject *__pyx_b;
static PyObject *__pyx_empty_tuple;
static int __pyx_lineno;
static int __pyx_clineno = 0;
static const char * __pyx_cfilenm= __FILE__;
static const char *__pyx_filename;
static const char **__pyx_f;

static void __Pyx_AddTraceback(const char *funcname); /*proto*/

/* Type declarations */
/* Module declarations from helloworld */

static int __pyx_f_10helloworld_hello(int, int); /*proto*/


/* Implementation of helloworld */

/* "/home/nosklo/devel/ctest/hello.pyx":1
 * cdef int hello(int a, int b):             # <<<<<<<<<<<<<<
 *     return a + b
 * 
 */

static  int __pyx_f_10helloworld_hello(int __pyx_v_a, int __pyx_v_b) {
  int __pyx_r;

  /* "/home/nosklo/devel/ctest/hello.pyx":2
 * cdef int hello(int a, int b):
 *     return a + b             # <<<<<<<<<<<<<<
 * 
 */
  __pyx_r = (__pyx_v_a + __pyx_v_b);
  goto __pyx_L0;

  __pyx_r = 0;
  __pyx_L0:;
  return __pyx_r;
}

static struct PyMethodDef __pyx_methods[] = {
  {0, 0, 0, 0}
};

static void __pyx_init_filenames(void); /*proto*/

#if PY_MAJOR_VERSION >= 3
static struct PyModuleDef __pyx_moduledef = {
    PyModuleDef_HEAD_INIT,
    "helloworld",
    0, /* m_doc */
    -1, /* m_size */
    __pyx_methods /* m_methods */,
    NULL, /* m_reload */
    NULL, /* m_traverse */
    NULL, /* m_clear */
    NULL /* m_free */
};
#endif
static int __Pyx_InitCachedBuiltins(void) {
  return 0;
  return -1;
}

static int __Pyx_InitGlobals(void) {
  return 0;
  return -1;
}

#if PY_MAJOR_VERSION < 3
PyMODINIT_FUNC inithelloworld(void); /*proto*/
PyMODINIT_FUNC inithelloworld(void)
#else
PyMODINIT_FUNC PyInit_helloworld(void); /*proto*/
PyMODINIT_FUNC PyInit_helloworld(void)
#endif
{
  __pyx_empty_tuple = PyTuple_New(0); 
  if (unlikely(!__pyx_empty_tuple))
      {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; 
       __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  /*--- Library function declarations ---*/
  __pyx_init_filenames();
  /*--- Initialize various global constants etc. ---*/
  if (unlikely(__Pyx_InitGlobals() < 0)) 
     {__pyx_filename = __pyx_f[0]; 
      __pyx_lineno = 1; 
      __pyx_clineno = __LINE__; 
      goto __pyx_L1_error;}
  /*--- Module creation code ---*/
  #if PY_MAJOR_VERSION < 3
  __pyx_m = Py_InitModule4("helloworld", __pyx_methods, 0, 0, PYTHON_API_VERSION);
  #else
  __pyx_m = PyModule_Create(&__pyx_moduledef);
  #endif
  if (!__pyx_m) 
     {__pyx_filename = __pyx_f[0]; 
      __pyx_lineno = 1; __pyx_clineno = __LINE__; 
      goto __pyx_L1_error;};
  #if PY_MAJOR_VERSION < 3
  Py_INCREF(__pyx_m);
  #endif
  __pyx_b = PyImport_AddModule(__Pyx_BUILTIN_MODULE_NAME);
  if (!__pyx_b) 
     {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; 
      __pyx_clineno = __LINE__; goto __pyx_L1_error;};
  if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) 
      {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; 
       __pyx_clineno = __LINE__; goto __pyx_L1_error;};
  /*--- Builtin init code ---*/
  if (unlikely(__Pyx_InitCachedBuiltins() < 0)) 
      {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; 
       __pyx_clineno = __LINE__; goto __pyx_L1_error;}
  __pyx_skip_dispatch = 0;
  /*--- Global init code ---*/
  /*--- Function export code ---*/
  /*--- Type init code ---*/
  /*--- Type import code ---*/
  /*--- Function import code ---*/
  /*--- Execution code ---*/

  /* "/home/nosklo/devel/ctest/hello.pyx":1
 * cdef int hello(int a, int b):             # <<<<<<<<<<<<<<
 *     return a + b
 * 
 */
  #if PY_MAJOR_VERSION < 3
  return;
  #else
  return __pyx_m;
  #endif
  __pyx_L1_error:;
  __Pyx_AddTraceback("helloworld");
  #if PY_MAJOR_VERSION >= 3
  return NULL;
  #endif
}

static const char *__pyx_filenames[] = {
  "hello.pyx",
};

/* Runtime support code */

static void __pyx_init_filenames(void) {
  __pyx_f = __pyx_filenames;
}

#include "compile.h"
#include "frameobject.h"
#include "traceback.h"

static void __Pyx_AddTraceback(const char *funcname) {
    PyObject *py_srcfile = 0;
    PyObject *py_funcname = 0;
    PyObject *py_globals = 0;
    PyObject *empty_string = 0;
    PyCodeObject *py_code = 0;
    PyFrameObject *py_frame = 0;

    #if PY_MAJOR_VERSION < 3
    py_srcfile = PyString_FromString(__pyx_filename);
    #else
    py_srcfile = PyUnicode_FromString(__pyx_filename);
    #endif
    if (!py_srcfile) goto bad;
    if (__pyx_clineno) {
        #if PY_MAJOR_VERSION < 3
        py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, 
             __pyx_cfilenm, __pyx_clineno);
        #else
        py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, 
             __pyx_cfilenm, __pyx_clineno);
        #endif
    }
    else {
        #if PY_MAJOR_VERSION < 3
        py_funcname = PyString_FromString(funcname);
        #else
        py_funcname = PyUnicode_FromString(funcname);
        #endif
    }
    if (!py_funcname) goto bad;
    py_globals = PyModule_GetDict(__pyx_m);
    if (!py_globals) goto bad;
    #if PY_MAJOR_VERSION < 3
    empty_string = PyString_FromStringAndSize("", 0);
    #else
    empty_string = PyBytes_FromStringAndSize("", 0);
    #endif
    if (!empty_string) goto bad;
    py_code = PyCode_New(
        0,            /*int argcount,*/
        #if PY_MAJOR_VERSION >= 3
        0,            /*int kwonlyargcount,*/
        #endif
        0,            /*int nlocals,*/
        0,            /*int stacksize,*/
        0,            /*int flags,*/
        empty_string, /*PyObject *code,*/
        __pyx_empty_tuple,  /*PyObject *consts,*/
        __pyx_empty_tuple,  /*PyObject *names,*/
        __pyx_empty_tuple,  /*PyObject *varnames,*/
        __pyx_empty_tuple,  /*PyObject *freevars,*/
        __pyx_empty_tuple,  /*PyObject *cellvars,*/
        py_srcfile,   /*PyObject *filename,*/
        py_funcname,  /*PyObject *name,*/
        __pyx_lineno,   /*int firstlineno,*/
        empty_string  /*PyObject *lnotab*/
    );
    if (!py_code) goto bad;
    py_frame = PyFrame_New(
        PyThreadState_GET(), /*PyThreadState *tstate,*/
        py_code,             /*PyCodeObject *code,*/
        py_globals,          /*PyObject *globals,*/
        0                    /*PyObject *locals*/
    );
    if (!py_frame) goto bad;
    py_frame->f_lineno = __pyx_lineno;
    PyTraceBack_Here(py_frame);
bad:
    Py_XDECREF(py_srcfile);
    Py_XDECREF(py_funcname);
    Py_XDECREF(empty_string);
    Py_XDECREF(py_code);
    Py_XDECREF(py_frame);
}

/* Type Conversion Functions */

static INLINE Py_ssize_t __pyx_PyIndex_AsSsize_t(PyObject* b) {
  Py_ssize_t ival;
  PyObject* x = PyNumber_Index(b);
  if (!x) return -1;
  ival = PyInt_AsSsize_t(x);
  Py_DECREF(x);
  return ival;
}

static INLINE int __Pyx_PyObject_IsTrue(PyObject* x) {
   if (x == Py_True) return 1;
   else if (x == Py_False) return 0;
   else return PyObject_IsTrue(x);
}

static INLINE PY_LONG_LONG __pyx_PyInt_AsLongLong(PyObject* x) {
    if (PyInt_CheckExact(x)) {
        return PyInt_AS_LONG(x);
    }
    else if (PyLong_CheckExact(x)) {
        return PyLong_AsLongLong(x);
    }
    else {
        PY_LONG_LONG val;
        PyObject* tmp = PyNumber_Int(x); if (!tmp) return (PY_LONG_LONG)-1;
        val = __pyx_PyInt_AsLongLong(tmp);
        Py_DECREF(tmp);
        return val;
    }
}

static INLINE unsigned PY_LONG_LONG __pyx_PyInt_AsUnsignedLongLong(PyObject* x) {
    if (PyInt_CheckExact(x)) {
        long val = PyInt_AS_LONG(x);
        if (unlikely(val < 0)) {
            PyErr_SetString(PyExc_TypeError, "Negative assignment to unsigned type.");
            return (unsigned PY_LONG_LONG)-1;
        }
        return val;
    }
    else if (PyLong_CheckExact(x)) {
        return PyLong_AsUnsignedLongLong(x);
    }
    else {
        PY_LONG_LONG val;
        PyObject* tmp = PyNumber_Int(x); if (!tmp) return (PY_LONG_LONG)-1;
        val = __pyx_PyInt_AsUnsignedLongLong(tmp);
        Py_DECREF(tmp);
        return val;
    }
}


static INLINE unsigned char __pyx_PyInt_unsigned_char(PyObject* x) {
    if (sizeof(unsigned char) < sizeof(long)) {
        long long_val = __pyx_PyInt_AsLong(x);
        unsigned char val = (unsigned char)long_val;
        if (unlikely((val != long_val)  || (long_val < 0))) {
            PyErr_SetString(PyExc_OverflowError, "value too large to convert to unsigned char");
            return (unsigned char)-1;
        }
        return val;
    }
    else {
        return __pyx_PyInt_AsLong(x);
    }
}

static INLINE unsigned short __pyx_PyInt_unsigned_short(PyObject* x) {
    if (sizeof(unsigned short) < sizeof(long)) {
        long long_val = __pyx_PyInt_AsLong(x);
        unsigned short val = (unsigned short)long_val;
        if (unlikely((val != long_val)  || (long_val < 0))) {
            PyErr_SetString(PyExc_OverflowError, "value too large to convert to unsigned short");
            return (unsigned short)-1;
        }
        return val;
    }
    else {
        return __pyx_PyInt_AsLong(x);
    }
}

static INLINE char __pyx_PyInt_char(PyObject* x) {
    if (sizeof(char) < sizeof(long)) {
        long long_val = __pyx_PyInt_AsLong(x);
        char val = (char)long_val;
        if (unlikely((val != long_val) )) {
            PyErr_SetString(PyExc_OverflowError, "value too large to convert to char");
            return (char)-1;
        }
        return val;
    }
    else {
        return __pyx_PyInt_AsLong(x);
    }
}

static INLINE short __pyx_PyInt_short(PyObject* x) {
    if (sizeof(short) < sizeof(long)) {
        long long_val = __pyx_PyInt_AsLong(x);
        short val = (short)long_val;
        if (unlikely((val != long_val) )) {
            PyErr_SetString(PyExc_OverflowError, "value too large to convert to short");
            return (short)-1;
        }
        return val;
    }
    else {
        return __pyx_PyInt_AsLong(x);
    }
}

static INLINE int __pyx_PyInt_int(PyObject* x) {
    if (sizeof(int) < sizeof(long)) {
        long long_val = __pyx_PyInt_AsLong(x);
        int val = (int)long_val;
        if (unlikely((val != long_val) )) {
            PyErr_SetString(PyExc_OverflowError, "value too large to convert to int");
            return (int)-1;
        }
        return val;
    }
    else {
        return __pyx_PyInt_AsLong(x);
    }
}

static INLINE long __pyx_PyInt_long(PyObject* x) {
    if (sizeof(long) < sizeof(long)) {
        long long_val = __pyx_PyInt_AsLong(x);
        long val = (long)long_val;
        if (unlikely((val != long_val) )) {
            PyErr_SetString(PyExc_OverflowError, "value too large to convert to long");
            return (long)-1;
        }
        return val;
    }
    else {
        return __pyx_PyInt_AsLong(x);
    }
}

static INLINE signed char __pyx_PyInt_signed_char(PyObject* x) {
    if (sizeof(signed char) < sizeof(long)) {
        long long_val = __pyx_PyInt_AsLong(x);
        signed char val = (signed char)long_val;
        if (unlikely((val != long_val) )) {
            PyErr_SetString(PyExc_OverflowError, "value too large to convert to signed char");
            return (signed char)-1;
        }
        return val;
    }
    else {
        return __pyx_PyInt_AsLong(x);
    }
}

static INLINE signed short __pyx_PyInt_signed_short(PyObject* x) {
    if (sizeof(signed short) < sizeof(long)) {
        long long_val = __pyx_PyInt_AsLong(x);
        signed short val = (signed short)long_val;
        if (unlikely((val != long_val) )) {
            PyErr_SetString(PyExc_OverflowError, "value too large to convert to signed short");
            return (signed short)-1;
        }
        return val;
    }
    else {
        return __pyx_PyInt_AsLong(x);
    }
}

static INLINE signed int __pyx_PyInt_signed_int(PyObject* x) {
    if (sizeof(signed int) < sizeof(long)) {
        long long_val = __pyx_PyInt_AsLong(x);
        signed int val = (signed int)long_val;
        if (unlikely((val != long_val) )) {
            PyErr_SetString(PyExc_OverflowError, "value too large to convert to signed int");
            return (signed int)-1;
        }
        return val;
    }
    else {
        return __pyx_PyInt_AsLong(x);
    }
}

static INLINE signed long __pyx_PyInt_signed_long(PyObject* x) {
    if (sizeof(signed long) < sizeof(long)) {
        long long_val = __pyx_PyInt_AsLong(x);
        signed long val = (signed long)long_val;
        if (unlikely((val != long_val) )) {
            PyErr_SetString(PyExc_OverflowError, "value too large to convert to signed long");
            return (signed long)-1;
        }
        return val;
    }
    else {
        return __pyx_PyInt_AsLong(x);
    }
}

static INLINE long double __pyx_PyInt_long_double(PyObject* x) {
    if (sizeof(long double) < sizeof(long)) {
        long long_val = __pyx_PyInt_AsLong(x);
        long double val = (long double)long_val;
        if (unlikely((val != long_val) )) {
            PyErr_SetString(PyExc_OverflowError, "value too large to convert to long double");
            return (long double)-1;
        }
        return val;
    }
    else {
        return __pyx_PyInt_AsLong(x);
    }
}
 16
Author: nosklo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-19 10:52:49

Una observación: Basado en el benchmarking realizado por los desarrolladores de pybindgen, no hay diferencia significativa entre boost.python y swig. No he hecho mi propia evaluación comparativa para verificar cuánto de esto depende del uso adecuado del impulso.funcionalidad python.

Tenga en cuenta también que puede haber una razón por la que pybindgen parece ser en general bastante más rápido que swig y boost.python: puede no producir un enlace tan versátil como los otros dos. Por ejemplo, propagación de excepciones, comprobación del tipo de argumento de llamada, etc. Aún no he tenido la oportunidad de usar Pybindgen, pero tengo la intención de hacerlo.

Boost es en general un paquete bastante grande para instalar, y la última vez que vi que no puedes instalar boost python, necesitas toda la biblioteca de Boost. Como otros han mencionado, la compilación será lenta debido al uso intensivo de la programación de plantillas, lo que también significa típicamente mensajes de error bastante crípticos en tiempo de compilación.

Resumen: dado lo fácil que es instalar SWIG y el uso, que genera un enlace decente que es robusto y versátil, y que un archivo de interfaz permite que su DLL de C++ esté disponible de varios otros lenguajes como LUA, C# y Java, yo lo favorecería sobre boost.python. Pero a menos que realmente necesite soporte en varios idiomas, echaría un vistazo de cerca a PyBindGen debido a su supuesta velocidad, y prestaría mucha atención a la robustez y versatilidad de encuadernación que genera.

 7
Author: schollii,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-02 15:58:44

Hay dragones aquí. No bebas, no subas. Para cualquier proyecto complicado, el código que tienes que rellenar para que funcione se vuelve inmanejable rápidamente. Si se trata de una API C simple para su biblioteca (sin clases), solo puede usar ctypes. Será fácil e indoloro, y no tendrá que pasar horas rastreando la documentación de estos laberínticos proyectos de envoltura tratando de encontrar la pequeña nota sobre la función que necesita.

 5
Author: Jorenko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-20 13:56:30

Ya que te preocupa la velocidad y la sobrecarga, sugiero considerar PyBindGen .

Tengo experiencia usándolo para envolver una gran biblioteca interna de C++. Después de probar SWIG, SIP, y Boost.Python Prefiero PyBindGen por las siguientes razones:

  1. Un wrapper de PyBindGen es pure-Python, no es necesario aprender otro formato de archivo
  2. PyBindGen genera llamadas a la API de Python C directamente, no hay una capa indirecta de robo de velocidad como SWIG.
  3. La C generada el código es limpio y fácil de entender. Me gusta Cython también, pero tratar de leer su salida C puede ser difícil a veces.
  4. Los contenedores de secuencia STL son compatibles (usamos muchos std::vectors)
 5
Author: sstock,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-26 05:07:53

Si no es una extensión grande, boost::python también podría ser una opción, se ejecuta más rápido que swig, porque controlas lo que está sucediendo, pero tomará más tiempo para dev.

De todos modos, la sobrecarga de swig es aceptable si la cantidad de trabajo dentro de una sola llamada es lo suficientemente grande. Por ejemplo, si el problema es que tiene algún bloque lógico de tamaño medio que desea mover a C / C++, pero ese bloque se llama dentro de un bucle cerrado, con frecuencia, es posible que tenga que evitar swig, pero realmente no puedo pensar en cualquier ejemplo del mundo real, excepto para sombreadores de gráficos con scripts.

 3
Author: Robert Gould,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-19 08:34:30

Antes de renunciar a su código python, eche un vistazo a ShedSkin. Afirman un mejor rendimiento que Psyco en algún código (y también afirman que todavía es experimental).

De lo contrario, hay varias opciones para enlazar código C/C++ a python.

Boost es largo de compilar, pero es realmente la solución más flexible y fácil de usar.

Nunca he usado SWIG, pero en comparación con boost, no es tan flexible como su marco de enlace genérico, no es un marco dedicado a python.

La siguiente opción es Pyrex. Permite escribir código pseudo python que se compila como una extensión C.

 3
Author: Philippe F,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-19 09:19:59