#python #c #cython
Есть функция на C: //my_f.h typedef void (*callback_t)(int result); void my_f(int a, int b, int c, callback_t cb); //my_f.c #include "my_f.h" void my_f(int a, int b, int c, callback_t cb) { cb(a * b + c); } собираем в библиотеку коммандой: gcc -shared -fPIC -o libmy_f.so my_f.c Теперь нужно из собранной библиотеки libmy_f.so правильно вызвать функцию my_f() в Python. Вопрос следущий -- как эту библиотеку правильно обернуть используя Cython?
Ответы
Ответ 1
Можно использовать boost, который позаботится о конвертировании типов и прочих жизненных радостях: Плюсовый код: std::string bar(const std::string& s) { return s + "!"; } BOOST_PYTHON_MODULE(foo) { using namespace boost::python; def("bar", bar); } Питоновый код: import foo print (foo.bar('what?'))Ответ 2
Чтобы только одну функцию вызвать, удобно ctypes использовать: #file: run_my_f_ctypes.py import ctypes @ctypes.CFUNCTYPE(None, ctypes.c_int) def callback(result): print(result) lib = ctypes.cdll.LoadLibrary('./libmy_f.so') lib.my_f(1, 2, 3, callback) # -> 5 Если нужно именно Cython использовать, то чтобы можно было бы передать обычную Питон-функцию, обратный вызов должен принимать void* аргумент -- пример. Если вы не можете интерфейс my_f библиотеки изменить, чтобы callback_t принимал бы void* параметр (через который можно Питон-функцию передать как показано в примере), то в качестве обходного решения (hack), можно через глобальную переменную функцию передать: #file: cy_my_f.pyx cdef extern from "my_f.h": ctypedef void (*callback_t)(int result) void my_f(int a, int b, int c, callback_t cb) def call_with_callback(a, b, c, callback): global py_callback py_callback = callback my_f(a, b, c, c_callback) cdef void c_callback(int result): py_callback(result) В этом случае только один вызов может быть активен одновременно. #!/usr/bin/env python3 #file: run_my_f.py import pyximport # $ pip install cython pyximport.install() # compile on-the-fly import cy_my_f cy_my_f.call_with_callback(1, 2, 3, print) # -> 5 Обратите внимание Питон-функция print передана как есть. Чтобы собрать cy_my_f Питон-модуль из cy_my_f.pyx, необходимо указать путь к my_f библиотеке: #file: cy_my_f.pyxbld import os from distutils.extension import Extension dirname = os.path.dirname(__file__) def make_ext(modname, pyxfilename): return Extension(name=modname, sources=[pyxfilename], libraries=["my_f"], include_dirs=[dirname], # where my_f.h library_dirs=[dirname], # where -lmy_fy ) def make_setup_args(): return dict(script_args=["--verbose"]) Во время import cy_my_f, pyximport (часть cython) автоматически использует cy_my_f.pyxbld, чтобы собрать cy_my_f модуль расширения для CPython, определённый в cy_my_f.pyx файле.
Комментариев нет:
Отправить комментарий