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

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

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

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

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

7 ответов


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

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

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

глоток: не играть ну с 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. Я могу рекомендовать его для взаимодействия с внешними библиотеками.

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

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

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

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


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


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

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

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

я реализовал что-то похожее на то, что вам нужно. У меня есть функция на 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;
}

в этом случае изображение является объектом C++, подверженным python( изображение с плавающими пикселями), а 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-расширения Python позволю тебе сделать то, что вы хотите, но с некоторым количеством хлопот.

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


f2py (часть numpy) является более простой альтернативой для глотка и повышения.python для обертывания кода C / Fortran number-crunching.


по моему опыту, есть два простых способа вызова кода 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 довольно либеральен в разрешении функций, функторов, объектов для передачи функциям и методам, тогда как я подозреваю, что то же самое не верно для say C или Fortran.

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

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


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