我想
sum_list
求和列表的函数,名为 sum_list.csum_list.c
文件设为 sum_list.sosum_list = ctypes。CDLL('./sum_list.so')
result = sum_list.sum_list([1, 2, 3])
它在步骤4中引发错误:
ctypes。ArgumentError:参数1::不知道如何转换参数1
当我用c编写一个函数,将两个数字相加时,它可以正常工作。
所以,重点是我不知道怎么把一个list (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;
}
python代码
from ctypes import CDLL
sum_list = CDLL('./sum_list.so')
l = [1, 2, 3]
sum_list.sum_list(l)
我希望我的 python 代码中的 var
结果是 6
。
正如另一个答案所提到的,您可以使用ctypes.py_object
来表示一个实际的Python对象,但是您还必须记住,在调用Python C API时,您不能释放GIL(全局解释器锁)。使用PyDLL
而不是CDLL
来完成这一点。
这是一个完全工作的示例,适用于一般的序列:
测试c
#include <Python.h>
#ifdef _WIN32
# define API __declspec(dllexport)
#else
define API
#endif
API long sum_list(PyObject* o)
{
Py_ssize_t i, n;
long total = 0, value;
PyObject* list;
PyObject* item;
list = PySequence_Fast(o,"not a sequence"); // New reference! Must DECREF eventually.
if(list == NULL)
return -1;
n = PySequence_Fast_GET_SIZE(list);
for (i = 0; i < PySequence_Fast_GET_SIZE(list); i++) {
item = PySequence_Fast_GET_ITEM(list, i);
if (!PyLong_Check(item))
{
PyErr_SetString(PyExc_TypeError,"sequence contains non-integer");
Py_DECREF(list);
return -1;
}
value = PyLong_AsLong(item);
if (value == -1 && PyErr_Occurred())
{
Py_DECREF(list);
return -1;
}
total += value;
}
Py_DECREF(list);
return total;
}
test.py
from ctypes import *
dll = PyDLL('test')
dll.sum_list.restype = c_long
dll.sum_list.argtypes = py_object,
print(dll.sum_list((1,2,3,4,5)))
try:
print(dll.sum_list(7))
except TypeError as e:
print(e)
try:
print(dll.sum_list((1,2,'a',4,5)))
except TypeError as e:
print(e)
try:
print(dll.sum_list((1,2,0x80000000,4,5)))
except OverflowError as e:
print(e)
try:
print(dll.sum_list((1,2,-0x80000001,4,5)))
except OverflowError as e:
print(e)
输出:
15
not a sequence
sequence contains non-integer
Python int too large to convert to C long
Python int too large to convert to C long
我已经投票给了@Antii的答案,但仍然想添加一个简短、完整且独立的示例。
首先,ctypes
是与C代码交互,而C代码是在没有考虑Python互操作性的情况下编写的。通常,这意味着代码不包含
/**
* Sample function to call from Python 3
* Build:
* $ gcc -shared -o libmath.so -fPIC math.c
*
* See https://stackoverflow.com/a/14884166/4594973
*
**/
int add(int x, int y) {
return x + y;
}
虽然上面的代码很简单,但是您需要确保更复杂的代码能够正确编译。例如,如果您正在使用C编译器和/或正在使用C特有的特性(例如,类、方法重载等),那么您必须在构建库时公开一个C兼容的接口,因为C的名字混淆将使得事后几乎不可能找到函数。
在构建了上面的C代码之后,使用这个Python脚本来调用它:
#!/usr/bin/env python3
import ctypes
cmath = ctypes.CDLL('./libmath.so')
cmath.restype = ctypes.c_int
cmath.argtypes = [ctypes.c_int, ctypes.c_int]
x = 4
y = 5
r = cmath.add(x, y)
print(f'{x} + {y} = {r}')
从我的终端运行示例:
$ gcc -shared -o libmath.so -fPIC math.c
$ python3 math.py
4 + 5 = 9
ctypes库用于调用纯C库中的函数。您找到的示例是一个函数,它将进入Python扩展模块,并且可以在没有ctypes的情况下使用。Ctypes实际上有一个PyObject*
的类型,即Ctypes.py_object
。你需要将列表包装在这张纸上——小心确保它还活着!
在任何情况下,您几乎都必须使用resttype
和argtype
来提供函数的正确原型。
这是一个工作示例:
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注意到的,这里必须使用< code>PyDLL,以确保GIL不会被释放,因为函数没有获得它!
问题内容: 所以我想通过cython从c调用一些python代码。我设法从c调用cython代码。而且我还可以从cython调用python代码。但是,当我将它们全部加在一起时,会丢失一些东西。 这是我的python代码(): 这是我的cython“ bridge”(): 这是c代码(): 运行此命令时,出现以下异常: 我怀疑缺少的部分: 我还没打电话 我还没有 Cython没有产生任何东西- 不
本文向大家介绍Python使用ctypes调用C/C++的方法,包括了Python使用ctypes调用C/C++的方法的使用技巧和注意事项,需要的朋友参考一下 python使用ctypes调用C/C++ 1. ctpes介绍 ctypes is a foreign function library for Python. It provides C compatible data types, a
问题内容: 如果我有以下两套代码,如何将它们粘合在一起? 如何使用x中连续的元素列表调用c_function?我试图将x强制转换为c_void_p,但这没有用。 我也尝试使用类似 但这会出现语法错误。 C代码显然想要一个数组的地址。我如何做到这一点? 问题答案: 以下代码适用于任意列表:
问题内容: 构建与C或C ++库的Python绑定的最快方法是什么? (如果这很重要,我正在使用Windows。) 问题答案: Boost Python库是用于连接Python和C 的框架。它使您可以快速而无缝地将C 类的函数和对象暴露给Python,反之亦然,而无需使用特殊工具-仅使用C 编译器即可。它被设计为以非介入方式包装C 接口,因此您不必为了包装而完全更改C ++代码,从而使Boost.
问题内容: 我是Python的新手,并且正在学习教程。本教程中有一个示例: 现在,在教程中,。但就我而言,我得到以下错误: 问题答案: 好像你已经用指向类实例的相同名称遮盖了指向类的内置名称。这是一个例子: 我相信这是显而易见的。Python将对象名称(函数和类也是对象)存储在字典中(命名空间实现为字典),因此你可以在任何范围内重写几乎任何名称。它不会显示为某种错误。如你所知,Python强调“特
我有一个字符串类型的列,其中包含嵌套字典对象的元素列表。例如 这实际上是火花数据帧中的一列,它是字符串类型的。所以我想知道如何将字符串的内容转换为列表,以便我可以使用json.loads.转换列表中的每个元素 知道吗?