Прототипирование с кодом Python перед компиляцией

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

IIRC, один из оригинальных ремитов Python, был языком прототипирования, однако Python довольно либеральен в предоставлении функций, функторов, объектов, передаваемых функциям и методам, тогда как я подозреваю, что это не так, как говорят C или Fortran.

Что мне знать о проектировании функций / классов, которые я предполагаю, придется взаимодействовать с компилируемым языком? И сколько из этих потенциальных проблем решаются библиотеками, такими как cTypes, bgen, SWIG , Boost.Python , Cython или Python SIP ?

Для этого конкретного случая использования (подходящая библиотека) я представляю себе, что позволяет пользователям определять математические функции (гуассианские, лоренцевые и т. Д.) Как функции Python, которые затем могут передаваться интерпретируемым библиотекой скомпилированного кода. Передача и возврат массивов также важны.

7 Solutions collect form web for “Прототипирование с кодом Python перед компиляцией”

Наконец, вопрос, на который я действительно могу ответить на значение.

Я изучил f2py, boost.python, swig, cython и pyrex для моей работы (PhD в методах оптических измерений). Я использовал swig экстенсивно, boost.python некоторые и pyrex и cython много. Я также использовал ctypes. Это моя разбивка:

Отказ от ответственности : Это мой личный опыт. Я не участвую ни в одном из этих проектов.

swig: не хорошо работает с c ++. Это должно было, но проблемы с изменением названия на этапе связывания были основной головной болью для меня в Linux и Mac OS X. Если у вас есть код C и вы хотите, чтобы он взаимодействовал с python, это хорошее решение. Я завернул GTS для своих нужд и вам нужно было написать основную библиотеку C, к которой я мог бы подключиться. Я бы не рекомендовал его.

Ctypes: Я написал библиотеку libdc1394 (IEEE Camera library) с использованием ctypes, и это было очень непростое. Код можно найти на https://launchpad.net/pydc1394 . Очень много работы по преобразованию заголовков в код python, но тогда все работает надежно. Это хороший способ, если вы хотите связать внешнюю библиотеку. Ctypes также находится в stdlib python, поэтому каждый может сразу использовать ваш код. Это также хороший способ быстро поиграть с новой lib в python. Я могу порекомендовать его для взаимодействия с внешними библиотеками.

Boost.Python : Очень приятно. Если у вас уже есть собственный код на C ++, который вы хотите использовать в python, пойдите для этого. Таким образом, очень легко перевести структуры классов c ++ в структуры классов python. Я рекомендую его, если у вас есть код c ++, который вам нужен в python.

Pyrex / Cython: используйте Cython, а не Pyrex. Период. Cython является более продвинутым и более приятным в использовании. В настоящее время я делаю все с помощью cython, с которым я работал с SWIG или Ctypes. Это также лучший способ, если у вас есть код Python, который работает слишком медленно. Этот процесс абсолютно фантастичен: вы конвертируете свои модули python в модули cython, создаете их и сохраняете профилирование и оптимизацию, как будто это все еще был python (без изменения необходимых инструментов). Затем вы можете применить столько (или как мало) C-кода, смешанного с вашим кодом на Python. Это намного быстрее, чем переписывать целые части вашего приложения в C; вы только переписываете внутренний цикл.

Сроки : ctypes имеет наивысшую накладную стоимость (~ 700 нс), за которой следует boost.python (322ns), а затем непосредственно swig (290ns). Cython имеет самую низкую накладную стоимость (124ns) и лучшую обратную связь, где она проводит время (поддержка cProfile!). Цифры из моего окна вызывают тривиальную функцию, которая возвращает целое число из интерактивной оболочки; поэтому накладные расходы на импорт модуля не синхронизированы, но только служебные вызовы функций. Поэтому проще всего и наиболее продуктивно быстро получить код python путем профилирования и использования cython.

Резюме : Для вашей проблемы используйте Cython;). Я надеюсь, что это краткое изложение будет полезно для некоторых людей. Я с удовольствием отвечу на оставшийся вопрос.


Изменить : я забыл упомянуть: для численных целей (то есть для соединения с NumPy) используйте Cython; они поддерживают его (потому что они в основном разрабатывают cython для этой цели). Таким образом, это должно быть еще 1 для вашего решения.

Я не использовал SWIG или SIP, но я нахожу написание обложек Python с boost.python, чтобы быть очень мощным и относительно простым в использовании.

Я не совсем понимаю, каковы ваши требования для передачи типов между C / C ++ и python, но вы можете сделать это легко, выставив C ++-тип в python или используя общий аргумент boost :: python :: object для вашего C ++ API. Вы также можете регистрировать преобразователи для автоматического преобразования типов python в типы C ++ и наоборот.

Если вы планируете использовать boost.python, учебное пособие – хорошее место для начала.

Я реализовал нечто похожее на то, что вам нужно. У меня есть функция C ++, которая принимает функцию python и изображение как аргументы, и применяет функцию python к каждому пикселю изображения.

Image* unary(boost::python::object op, Image& im) { Image* out = new Image(im.width(), im.height(), im.channels()); for(unsigned int i=0; i<im.size(); i++) { (*out)[i] == extract<float>(op(im[i])); } return out; } 

В этом случае Image является объектом C ++, подверженным python (изображение с пикселями float), а op – функция, определенная на основе python (или действительно любой объект python с атрибутом __call__). Затем вы можете использовать эту функцию следующим образом (при условии, что унарное устройство находится в вызываемом изображении, которое также содержит изображение и функцию загрузки):

 import image im = image.load('somefile.tiff') double_im = image.unary(lambda x: 2.0*x, im) 

Что касается использования массивов с boost, я лично этого не делал, но я знаю, что функциональность для предоставления массивов на python с использованием boost доступна – это может быть полезно.

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

Это обеспечит сопоставление «один к одному» из вашего кода прототипа Python до возможного скомпилированного кода и позволит вам легко использовать ctypes и избежать целых кучей головных болей.

Для максимальной установки вам почти наверняка понадобится использовать массивы, что немного усложнит ситуацию, но все еще очень подходит для ctypes.

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

Для того, что вы делаете, вы также можете проверить NumPy , который может выполнять некоторую работу, которую вы хотите нажать на C, а также предложить дополнительную помощь в перемещении данных между Python и C.

f2py (часть numpy ) является более простой альтернативой SWIG и boost.python для обертывания кода хруста числа C / Fortran.

По моему опыту, есть два простых способа вызова кода C из кода Python. Существуют и другие подходы, все из которых более раздражающие и / или многословные.

Первое и самое простое – собрать кучу C-кода в виде отдельной общей библиотеки, а затем вызвать функции в этой библиотеке с помощью ctypes. К сожалению, прохождение чего-либо другого, кроме базовых типов данных, является нетривиальным.

Второй самый простой способ – написать модуль Python в C, а затем вызвать функции в этом модуле. Вы можете передать все, что захотите, этим функциям C, не перепрыгивая через любые обручи. И легко назвать функции или методы Python из этих C-функций, как описано здесь: https://docs.python.org/extending/extending.html#calling-python-functions-from-c

У меня недостаточно опыта работы с SWIG, чтобы предлагать интеллектуальные комментарии. И хотя можно делать такие вещи, как передавать пользовательские объекты Python в C-функции через ctypes или определять новые классы Python на C, эти вещи раздражают и многословны, и я рекомендую использовать один из двух подходов, описанных выше.

Python довольно либерально разрешает передавать функции, функторы, объекты в функции и методы, тогда как я подозреваю, что это не так, как говорят C или Fortran.

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

Я не знаю, насколько это поможет, когда вы пытаетесь интегрировать код C и Python, но я просто хотел прояснить одно заблуждение.

В дополнение к вышеприведенным инструментам я могу порекомендовать использовать Pyrex (для создания модулей расширения Python) или Psyco (как JIT-компилятор для Python).

  • Каков наилучший способ вернуть строку в интерфейс SWIG python?
  • Освобождение Python GIL в коде C ++
  • Использование обернутых SWIG-функций из Windows .dll
  • Как сделать SWIG в VS2010?
  • Как правильно обернуть std :: vector <std :: size_t> с помощью SWIG для Python? Проблемы с std :: size_t
  • (SWIG) Передача строки const из Python
  • Как обрабатывать unique_ptr с помощью SWIG
  • Доступ к C ++ typedef в Python с использованием SWIG
  • Python - лучший язык программирования в мире.