Подтвердить что ты не робот

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

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

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

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

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

4b9b3361

Ответ 1

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

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

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

SWIG: не играет хорошо с С++. Это должно, но проблемы с изменением названия на этапе связывания были основной головной болью для меня в 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: Очень приятно. Если у вас уже есть собственный код на С++, который вы хотите использовать в python, пойдите для этого. Таким образом, очень легко перевести структуры классов С++ в структуры классов python. Я рекомендую его, если у вас есть код С++, который вам нужен в python.

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

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

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


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

Ответ 2

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

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

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

Я реализовал нечто похожее на то, что вам нужно. У меня есть функция С++, которая принимает функцию 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 является объектом С++, подверженным 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 доступна - this может быть полезно.

Ответ 3

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

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

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

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

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

Ответ 4

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

Ответ 5

По моему опыту, есть два простых способа вызова кода 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, эти вещи раздражают и многословны, и я рекомендую использовать один из двух подходов, описанных выше.

Ответ 6

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

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

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

Ответ 7

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