Обертывание функции, которая возвращает указатель на объект python с ctypes - PullRequest
1 голос
/ 17 января 2011

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

Проблема в том, что PyUFunc_FromFuncAndData возвращает указатель на PyObject. Можно ли использовать его как объект из кода Python?

По сути, я хотел бы иметь возможность перевести следующий код Cython в python / ctypes:

from numpy cimport NPY_DOUBLE
from libc.stdlib cimport malloc, free

cdef extern from "numpy/ufuncobject.h":
    ctypedef void (*PyUFuncGenericFunction) (char **, Py_ssize_t *, Py_ssize_t *, void *)
    object PyUFunc_FromFuncAndData (PyUFuncGenericFunction *, void **, char *, int, int, int, int, char *, char *, int)
    void import_ufunc()

import_ufunc()


cdef class UFuncWrapper:

    cdef readonly object func
    cdef object _llvm_func
    cdef PyUFuncGenericFunction function
    cdef char *types
    cdef bytes name

    def __init__(self, func, ufunc, long long ptr):
        self._llvm_func = ufunc # keep a ref to prevent it from being gced
        cdef int num_args = len(func.args)
        self.types = <char*>malloc(sizeof(char)*(num_args+1))
        self.name = func.name
        cdef int i
        for i in range(num_args+1):
            self.types[i] = NPY_DOUBLE
        self.function = <PyUFuncGenericFunction>ptr
        self.func = PyUFunc_FromFuncAndData(
            &self.function,
            NULL,
            self.types,
            1,  #ntypes
            num_args,
            1,
            -1, # PyUFunc_None,
            self.name,
            self.name,   #FIXME: __doc__
            0)

    def __dealloc__(self):
        free(self.types)

    def __call__(self, *args):
        return self.func(*args)

1 Ответ

3 голосов
/ 02 марта 2011

Установите для restype этой функции значение ctypes.py_object. В следующем примере используется вызов Python C-API, но он работает так же для всего остального.

import ctypes
class Foo(object):
    bar='baz'

foo=ctypes.py_object(Foo)
print 'Memory adress of Foo.bar object:',
print ctypes.pythonapi.PyObject_GetAttrString(foo,'bar') # prints the pointer

ctypes.pythonapi.PyObject_GetAttrString.restype = ctypes.py_object

print 'Actual Foo.bar after we set restype correctly:', 
print ctypes.pythonapi.PyObject_GetAttrString(foo,'bar') # prints "baz"
...