Расширение Python - чтобы потянуть, не потянуть или Cython

63
задан JBentley 12 April 2014 в 13:27
поделиться

8 ответов

Наверняка у Вас всегда будет увеличение производительности, делающее это вручную, но усиление будет очень маленьким по сравнению с усилием, требуемым сделать это. У меня нет числа, чтобы дать Вам, но я не рекомендую это, потому что необходимо будет поддержать интерфейс вручную, и это не опция, если модуль является большим!

Вы сделали правильную вещь к, принял решение использовать язык сценариев, потому что Вы хотели быструю разработку. Таким образом, Вы избежали синдрома оптимизации на ранней стадии, и теперь Вы хотите оптимизировать части узкого места, большие! Но если Вы сделаете интерфейс C/python вручную, то Вы упадете при синдроме оптимизации на ранней стадии наверняка.

, Если Вы хотите что-то с меньшим количеством интерфейсного кода, можно думать о создании dll от кода C и пользоваться той библиотекой непосредственно из Python с cstruct.

Рассматривают также Cython, если Вы хотите использовать только код Python в своей программе.

26
ответ дан Mike Pennington 24 November 2019 в 16:12
поделиться

Необходимо рассмотреть Повышение. Python, если Вы не планируете генерировать привязку для других языков также с большим глотком.

, Если у Вас есть много функций и классов для привязки, , Py ++ является большим инструментом, который автоматически генерирует необходимый код для создания привязки.

Pybindgen может также быть опцией, но это - новый проект и меньше завершенное то Повышение. Python.

<час>

Редактирование:

, Возможно, я должен быть более явным о про и недостатках.

  • Большой глоток:

    про: можно генерировать привязку для многих языков сценариев.

    недостатки: Мне не нравится способ, которым работает синтаксический анализатор. Я не знаю, был ли сделанный некоторые успехи, но два года назад синтаксический анализатор C++ вполне ограничен. Большую часть времени я имел к копии/прошлому, мои.h заголовки добавляют [приблизительно 110] символы и дают дополнительные подсказки синтаксическому анализатору большого глотка.

    я был также необходим для контакта с C-API Python время от времени для (не так) сложные преобразования типов.

    я не использую его больше.

  • Повышение. Python:

    про: это - очень полная библиотека. Это позволяет Вам делать почти все, что возможно с C-API, но в C++. Я никогда не должен был писать код C-API с этой библиотекой. Я также никогда не встречался с ошибкой из-за библиотеки. Код для привязки или работы как очарование или отказывается от компиляции.

    Это - вероятно, одно из лучших решений, в настоящее время доступных, если у Вас уже есть некоторая библиотека C++ для привязки. Но если бы у Вас только есть небольшая функция C для перезаписи, я, вероятно, попробовал бы Cython.

    недостатки: если у Вас нет предварительно скомпилированного Повышения. Библиотека Python Вы собираетесь использовать Bjam (вид делают замену). Я действительно ненавижу Bjam и его синтаксис.

    библиотеки Python, созданные с B.P, склонны становиться страдающими ожирением. Это также берет партия из времени для компиляции их.

  • Py ++ (прекращенный): это - Повышение. Python, сделанный легким. Py ++ использует синтаксический анализатор C++ для чтения кода и затем генерирует Повышение. Код Python автоматически. У Вас также есть большая поддержка от ее автора (не, это не я;-)).

    недостатки: только проблемы, должные Повысить. Сам Python. Обновление: По состоянию на 2014 этот проект теперь выглядит прекращенным.

  • Pybindgen:

    Это генерирует код, имеющий дело с C-API. Можно или описать функции и классы в файле Python, или позволить Pybindgen прочитать заголовки и генерировать привязку автоматически (для этого он использует pygccxml, библиотека Python записала автором Py ++).

    недостатки: это - молодой проект с меньшей командой, чем Повышение. Python. Существуют все еще некоторые ограничения: Вы не можете использовать множественное наследование для своих классов C++, Обратные вызовы (не автоматически, пользовательский код обработки обратного вызова может быть записан, хотя). Перевод исключений Python к C.

    Это определенно стоит хорошего взгляда.

  • А новый: 20.01.2009 автор Py ++ объявил новый пакет для взаимодействия через интерфейс кодом с C/C++ с Python. Это основано на ctypes. Я уже не попробовал его, но я буду!Примечание: этот проект смотрит discontiued как Py ++.

  • CFFI: Я не знал существование этого до самого последнего времени поэтому на данный момент, я не могу дать свое мнение. Похоже, что можно определить функции C в строках Python и назвать их непосредственно от того же модуля Python.

  • Cython: Это - метод, который я в настоящее время использую в своих проектах. В основном Вы пишете код в специальных .pyx файлах. Те файлы компилируются (переведенные) в код C, которые в свою очередь компилируются в модули CPython. Код Cython может быть похожим на обычный Python (и на самом деле чистый Python является допустимыми .pyx файлами Cython), но Вы можете также больше информации как типы переменных. Этот дополнительный ввод позволяет Cython генерировать быстрее C код. Код в файлах Cython может вызвать и чистые функции Python, но также и C и М функции C++ (и также методы C++).

    мне потребовалось некоторое время для размышления в Cython, которые в том же коде называют C и функцию C++, смешивают Python и переменные C и так далее. Но это - очень мощный язык с активным (в 2014) и дружелюбным сообществом.

62
ответ дан ascobol 24 November 2019 в 16:12
поделиться

Используя Cython довольно хорош. Можно записать расширение C с подобным Python синтаксисом и иметь его, генерируют код C. Шаблон включен. Так как у Вас уже есть код в Python, необходимо сделать, всего несколько изменений в коде узкого места и коде C будут сгенерированы от него.

Пример. hello.pyx:

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

, Который генерирует 601 строка из шаблонного кода:

/* 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
ответ дан nosklo 24 November 2019 в 16:12
поделиться

Так как Вы обеспокоены скоростью и наверху, я предлагаю рассмотреть PyBindGen .

у меня есть опыт с помощью него для обертывания крупной внутренней библиотеки C++. После попытки БОЛЬШОГО ГЛОТКА, SIP и Повышения. Python я предпочитаю PyBindGen по следующим причинам:

  1. А оберткой PyBindGen является чистый Python, никакая потребность изучить другой формат файла
  2. , PyBindGen генерирует вызовы API Python C непосредственно, нет никакого грабящего скорость косвенного слоя как БОЛЬШОЙ ГЛОТОК.
  3. сгенерированный код C является чистым и простым понять. Мне нравится Cython также, но пытающийся считать его вывод C может время от времени быть трудным.
  4. контейнеры последовательности STL поддерживаются (мы используем много станд.:: вектор)
6
ответ дан sstock 24 November 2019 в 16:12
поделиться

Здесь быть драконы. Не потягивайте, не повышайте. Для любого сложного проекта код необходимо заполнить себя, чтобы заставить их работать, становится неуправляемым быстро. Если это - простой API C к Вашей библиотеке (никакие классы), можно просто использовать ctypes. Это будет легким и безболезненным, и Вы не должны будете проводить часы, траля через документацию для этих лабиринтообразных проектов обертки, пытающихся найти одно крошечное примечание о функции, в которой Вы нуждаетесь.

5
ответ дан Jorenko 24 November 2019 в 16:12
поделиться

Если не большое расширение, повышение:: Python мог бы также быть опцией, он выполняется быстрее, чем большой глоток, потому что Вы управляете тем, что происходит, но он займет больше времени к dev.

Так или иначе издержки большого глотка приемлемы, если объем работы в единственном вызове является достаточно большим. Например, если Вы выходите, то, что у Вас есть некоторый логический блок среднего размера, который Вы хотите переместить в C/C++, но что блок называют в жестком цикле, часто, Вам, возможно, придется избежать большого глотка, но я не могу действительно думать ни о каких реальных примерах за исключением графических программ построения теней в виде сценария.

3
ответ дан Robert Gould 24 November 2019 в 16:12
поделиться

Перед отказыванием от Вашего кода Python взгляните на ShedSkin. Они требуют лучшей производительности, чем Psyco на некотором коде (и также заявляют, что это все еще экспериментально).

Еще, существует несколько вариантов для привязки кода C/C++ к Python.

Повышение долго для компиляции, но является действительно самым гибким и простым в использовании решением.

я никогда не использовал БОЛЬШОЙ ГЛОТОК, но выдерживал сравнение с повышением, это не столь гибко, как это - универсальная обязательная платформа, не платформа, выделенная Python.

Следующий выбор Пирекс . Это позволяет писать псевдо код Python, который компилируется как расширение C.

3
ответ дан Philippe F 24 November 2019 в 16:12
поделиться

Наблюдение: на основе тестирования, проведенного разработчиками pybindgen, нет значительной разницы между boost.python и swig. Я не проводил собственных тестов, чтобы проверить, насколько это зависит от правильного использования функций boost.python.

Обратите также внимание на то, что может быть причина, по которой pybindgen кажется в целом немного быстрее, чем swig и boost.python: он может не создавать такой универсальной привязки, как два других. Например, распространение исключений, проверка типа аргумента вызова и т. Д. У меня еще не было возможности использовать pybindgen, но я собираюсь это сделать.

Boost - это, как правило, довольно большой пакет для установки, и последнее, что я видел, вы не можете просто установить boost python, вам в значительной степени понадобится вся библиотека Boost.Как уже упоминалось другими, компиляция будет медленной из-за интенсивного использования шаблонного программирования, что также обычно означает довольно загадочные сообщения об ошибках во время компиляции.

Резюме: учитывая, насколько легко установить и использовать SWIG, что он генерирует достойную привязку, которая является надежной и универсальной, и что один интерфейсный файл позволяет вашей C ++ DLL быть доступной с нескольких других языков, таких как LUA, C # и Java, Я бы предпочел его boost.python. Но если вам действительно не нужна многоязычная поддержка, я бы внимательно посмотрел на PyBindGen из-за его предполагаемой скорости и обратил пристальное внимание на надежность и универсальность создаваемого им связывания.

7
ответ дан 24 November 2019 в 16:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: