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

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

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

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

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

19.08.2008 12:32:38
7 ОТВЕТОВ
РЕШЕНИЕ

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

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

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

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

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

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

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

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

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


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

35
2.11.2009 13:49:49
Очень ценный обзор, спасибо. Есть ли у вас опыт работы с разобранными шаблонами C ++? Я знаю, что метод повышения - это метапрограммирование шаблонов, но поддерживают ли они на самом деле демонстрацию библиотек с метапрограммированием шаблонов? Кроме того, какие-либо изменения в списке за последние 18 месяцев?
daspostloch 20.04.2011 09:06:08
Нет, без изменений. Все еще стоит, но я не работал ни с ctypes, ни с swig в прошлом году. Cython поддерживает шаблоны в настоящее время вполне разумно, поэтому я бы, наверное, пошел сюда. Однако у меня нет сильно шаблонного кода (только некоторые контейнерные классы), поэтому здесь нет никакого реального опыта.
SirVer 24.04.2011 12:53:42
Я также обернул некоторые большие библиотеки C, используя ctypes, и я указываю будущим людям на code.google.com/p/ctypesgen, что это было спасение жизни .
Brian Larsen 18.10.2012 17:28:50

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

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

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

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

1
14.11.2014 01:47:04

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

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

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

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

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

6
14.11.2014 01:46:40

Я не использовал 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 (изображение с плавающими пикселями), а op - это определенная Python-функция (или действительно любой объект Python с атрибутом __call__). Затем вы можете использовать эту функцию следующим образом (предполагая, что унарный находится в вызываемом образе, который также содержит Image и функцию загрузки):

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

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

10
26.08.2008 16:48:13

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

4
29.09.2008 22:30:59

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

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

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

0
29.09.2008 22:52:19

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

0
16.05.2009 15:08:53