首页 > 解决方案 > 通过 ctypes 从 Python 调用 C 代码,使用 python 对象列表

问题描述

我想要

  1. 用 c写一个sum_listsum 一个列表的函数,命名为 sum_list.c
  2. sum_list.c文件制作为 sum_list.so
  3. sum_list = ctypes.CDLL('./sum_list.so')
  4. result = sum_list.sum_list([1, 2, 3])

它在步骤 4 中引发错误:

ctypes.ArgumentError: 参数 1: : 不知道如何转换参数 1

当我在 c 中编写一个添加两个数字的函数时,它可以正常工作。

所以,关键是我不知道如何将列表(python 对象)传递给 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;
}

蟒蛇代码

from ctypes import CDLL

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

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

我希望var我的 python 代码中的结果是6.

标签: pythoncpython-3.xctypes

解决方案


ctypes 库用于调用纯 C 库中的函数。您找到的示例是用于将进入 Python 扩展模块的函数,并且可以在没有 ctypes 的情况下使用。Ctypes 实际上有一个类型 for PyObject *,即ctypes.py_object。您需要将列表包装在其中 - 小心确保它会保持活动状态!

restype在任何情况下,您几乎总是必须使用and提供正确的函数原型argtypes

这是一个工作示例:

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)))

请注意,正如 Mark 所指出的,您必须PyDLL在此处改用,以确保不会释放 GIL,因为该函数没有获取它!


推荐阅读