Как вернуть указатель на функцию из CPython в Python, а затем вызвать функцию C с ctypes? - PullRequest
3 голосов
/ 01 марта 2011

У меня есть функция CPython:

void my_cfunc(int arg)
{
  printf("Hello from C; arg=%d\n", arg);
}

PyObject *get_fptr(PyObject * /*self*/, PyObject * /*args*/)
{
    return PyCObject_FromVoidPtr(my_cfunc, NULL);
}

Тогда позже в Python у меня будет:

import mymodule

ptr = mymodule.get_fptr() # will return a PyCObject wrapping the C function pointer

Потом позже:

from ctypes import *

SOMEFUNC_T = CFUNCTYPE(c_void, c_int)
somefunc = SOMEFUNC_T(ptr) # <-- bad!

Теперь, если я изменю get_fptr так, чтобы он возвращался как: PyLong_FromSize_t (size_t (my_cfunc)), тогда 'somefunc' будет действительным.

Но я не хочу приводить указатель функции к size_t.

Пожалуйста, сообщите

1 Ответ

1 голос
/ 02 марта 2011

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

Во-вторых, это не похоже, что ctypes вообще поддерживает PyCObject.Ваш вызов CFUNCTYPE (None, c_int) [я заменил c_void на None] с аргументом PyCObject, терпит неудачу, потому что CFUNCTYPE ожидает целое число и не знает, что делать с PyCObject.

Почему бы не написать оболочку Pythonвместо my_cfunc, который вы будете вызывать из Python без хлопот ctypes?Например:

PyObject *call_fptr(PyObject *self, PyObject *args)
{
    int arg;
    if (!PyArg_ParseTuple(args, "i", &arg))
        return NULL;

    my_cfunc(arg);
    Py_RETURN_NONE;
}

В качестве бонуса, если вам нравится ctypes, обертку Python для my_func можно использовать для создания экземпляра внешней функции ctypes (в отличие от PyCObject)!

from ctypes import *
import foo

SOMEFUNC_T = CFUNCTYPE(None, c_int)
cfunc = SOMEFUNC_T(foo.call_fptr)
cfunc(1)

Редактировать: Указание, что функция C должна принимать переменное число аргументов, усложняет ваш вопрос ... Как бы вы все-таки обернули свою переменную функцию C-аргумента ctypes, учитывая, что CFUNCTYPE требует известного набораarguments?

Проблема в этом случае действительно сводится к преобразованию кортежа Python в список переменных аргументов в C, который, по-видимому, совсем не тривиален.Фактически SWIG посвятил этой проблеме раздел своей документации , например, так: Большинство других инструментов генерации оболочек мудро выбрали, чтобы избежать этой проблемы .

Тем не менее, он дает совет, что можно динамически создавать списки переменных аргументов в переносимой форме с помощью libffi .

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

...