1

I'm trying to call a Python function in C using Python C API. I use PyObject_Call to call the Python function which returns me a PyObject. If the returned PyObject is a numpy array or a list then how should I handle it? Basically if I want to cast it into a C array, or just get the pointer out, how should I do it?

Here is an outline of the code. The func is numpy.power.

double Array[4] = {1.0, 2.0, 3.0, 4.0};
int Integer = 2;

double *call_func(PyObject *func, double array[], int integer){
    PyObject *args;
    PyObject *kwargs;
    PyObject *result;
    npy_intp dims[1] = {4};
    double *retval;

    PyGILState_STATE state = PyGILState_Ensure();

    args = Py_BuildValue("(Od)", PyArray_SimpleNewFromData(1, dims, NPY_DOUBLE, Array), integer);
    kwargs = NULL;

    result = PyObject_Call(func, args, kwargs);
    Py_DECREF(args);
    Py_XDECREF(kwargs);

    retval = ???
    Py_DECREF(result);

    PyGILState_Release(state);
    return retval;
} 

...
snsunx
  • 155
  • 1
  • 9
  • 1
    Check out `PyArray_CheckExact` and `PyArray_DATA` http://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_CheckExact and http://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_DATA – Alok-- Jun 27 '16 at 18:12
  • @Alok-- But my return type from `PyObject_Call` is PyObject not PyArrayObject so I don't know if I can use this. – snsunx Jun 27 '16 at 20:15
  • It's supposed to be used on a `PyObject *`: see https://github.com/numpy/numpy/blob/master/numpy/core/include/numpy/ndarrayobject.h#L35 for the definition. https://github.com/numpy/numpy/blob/master/numpy/core/src/multiarray/number.c#L89 is an example of its use on `PyObject *`. – Alok-- Jun 27 '16 at 20:53
  • @Alok-- I tried that but it did require a `PyArrayObject *`. The error is following `passing argument 1 of ‘PyArray_DATA’ from incompatible pointer type /share/apps/anaconda2/pkgs/numpy-1.10.4-py27_1/lib/python2.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1437: note: expected ‘struct PyArrayObject *’ but argument is of type ‘struct PyObject *’` – snsunx Jun 28 '16 at 21:30
  • @Alok-- I think it's not an error but a warning. It should be fine. – snsunx Jun 28 '16 at 23:07
  • Yeah, that's standard. Once you check that a `PyObject *` actually points to a numpy array, you can safely cast it to `PyArrayObject *`. If you want, you can also use a new pointer so that you don't have to cast: `PyObject *o = ...;`, and after checking that `o` is an array: `PyArrayObject *a = (PyArrayObject *) o;`. Now you can use `a` when you need a `PyArrayObject *` in numpy C api. – Alok-- Jun 29 '16 at 20:00
  • See http://docs.scipy.org/doc/numpy/reference/c-api.types-and-structures.html (discussion under "Python Types and C-Structures"). Also see `PyArrayObject` section on the same page and note that it starts with `PyObject_HEAD`. Finally, see https://docs.python.org/2/c-api/structures.html#c.PyObject. Basically, if you have a numpy array, in C, the struct's first two fields are going to be the same as that of a `PyObject`. Once you are sure that it's a numpy array, you can be sure that it has other fields that come from a `PyArrayObject` type. – Alok-- Jun 29 '16 at 20:01

1 Answers1

0

If the object is Numpy array, so I think this will help you. But you should notice the fucntion:

void* PyArray_GetPtr(PyArrayObject* aobj, npy_intp* ind)

It will help you manipulate numpy array.

If it's a list, then you will need the functions from this link to manipulate your object.

You will manage to get the pointer to the item and convert it back to C object.

nguyeh
  • 63
  • 1
  • 8