Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

call C code from Python via ctypes, use python object list

I want to

  1. write a function sum_list of sum a list in c, named sum_list.c
  2. make the sum_list.c file to sum_list.so
  3. sum_list = ctypes.CDLL('./sum_list.so')
  4. result = sum_list.sum_list([1, 2, 3])

It raise error in step 4:

ctypes.ArgumentError: argument 1: : Don't know how to convert parameter 1

when I write a function in c which add two numbers, it works ok.

so, the point is i don't know how to pass a list (python object) to c.


sum_list.c

#define PY_SSIZE_T_CLEAN
#include <Python.h>

long sum_list(PyObject *list)
{
    Py_ssize_t i, n;
    long total = 0, value;
    PyObject *item;

    n = PyList_Size(list);
    if (n < 0)
        return -1; /* Not a list */
    for (i = 0; i < n; i++) {
        item = PyList_GetItem(list, i); /* Can't fail */
        if (!PyLong_Check(item)) continue; /* Skip non-integers */
        value = PyLong_AsLong(item);
        if (value == -1 && PyErr_Occurred())
            /* Integer too big to fit in a C long, bail out */
            return -1;
        total += value;
    }
    return total;
}

python code

from ctypes import CDLL

sum_list = CDLL('./sum_list.so')

l = [1, 2, 3]
sum_list.sum_list(l)

I expect the var result in my python code is 6.

like image 365
kun Avatar asked Dec 31 '22 22:12

kun


1 Answers

The ctypes library is meant for calling functions in pure C libraries. The example that you found is for a function that would go into a Python extension module, and be usable without ctypes. Ctypes actually has a type for PyObject *, namely ctypes.py_object. You need to wrap the list in this - be careful to ensure that it will stay alive!

In any case you must almost always provide the correct prototype of the function using the restype and argtypes.

Here's a working example:

import ctypes

sum_list = ctypes.PyDLL('./sum_list.so')
sum_list.restype = ctypes.c_long
sum_list.argtypes = [ ctypes.py_object ]

l = [1, 2, 3]
print(sum_list.sum_list(ctypes.py_object(l)))

Note, as noticed by Mark, you must use PyDLL here instead, to ensure that the GIL is not released since the function does not acquire it!



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!