开发者

Wrapping a function which returns a pointer to a python object with ctypes

开发者 https://www.devze.com 2023-02-05 07:19 出处:网络
I\'ve got some code which comp开发者_运维技巧iles a C function to create a numpy generic function with it using PyUFunc_FromFuncAndData. I\'ve written some cython to create the ufunc but I\'d like to

I've got some code which comp开发者_运维技巧iles a C function to create a numpy generic function with it using PyUFunc_FromFuncAndData. I've written some cython to create the ufunc but I'd like to do it with ctypes if possible since I'm intending to distribute it and I'd like to avoid users the compile step.

The problem is that PyUFunc_FromFuncAndData returns a pointer to a PyObject. Is it possible to use it as an object from python code?

Basically, I'd like to be able to translate the following cython code to 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)


Set restype of that function to ctypes.py_object. The following example uses a call to python C-API but it works the same for anything else.

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"
0

精彩评论

暂无评论...
验证码 换一张
取 消