在Python类中封装ctypes.Structure时遇初始化错误求助
问题:封装ctypes结构体到Python类时出现"too many initializers"错误
问题背景
需要通过ctypes.Structure向C语言传递结构体,Jupyter中的示例代码可正常运行,但封装为Python类时触发TypeError: too many initializers错误。
C语言代码(test.c)
struct DATA; typedef struct DATA { int n; double *ina; double *outa; } DATA; void square_array2(DATA *data) { int i; for (i=0; i<data->n; i++) { data->outa[i] = data->ina[i]*data->ina[i]; } }
编译命令
gcc -shared -fPIC test.c -o test.so
可正常运行的Jupyter代码
import importlib import numpy as np import ctypes from ctypes import CDLL, POINTER from ctypes import c_size_t, c_double from wurlitzer import pipes, STDOUT %reload_ext wurlitzer
testlib = CDLL('test.so')
n=5 ina = np.linspace(1.0,5.0,n) outa = np.zeros(n,np.float64) class Data(ctypes.Structure): _fields_ = [("n", ctypes.c_int), ("ina", ctypes.POINTER(ctypes.c_double)), ("outa", ctypes.POINTER(ctypes.c_double))] data = Data(n,np.ctypeslib.as_ctypes(ina),np.ctypeslib.as_ctypes(outa)) print("initial array",ina) testlib.square_array2.restype = None testlib.square_array2(ctypes.byref(data)) print("final array",outa)
出错的封装类代码
import ctypes from ctypes import CDLL, POINTER from ctypes import c_size_t, c_double, c_int from io import StringIO from wurlitzer import pipes, STDOUT class Data(ctypes.Structure): _fields_ = [("n", ctypes.c_int), ("ina", ctypes.POINTER(ctypes.c_double)), ("outa", ctypes.POINTER(ctypes.c_double))] class testClib(Data): #尝试继承Data类 def __init__(self): # 加载库 self.lib = CDLL("test.so") def square_array2(self,ina,outa): n, = ina.shape # 出错的代码行 data = Data(n,np.ctypeslib.as_ctypes(ina),np.ctypeslib.as_ctypes(outa)) out = StringIO() with pipes(stdout=out, stderr=STDOUT): self.lib.square_array2.restype = None self.lib.square_array2(ctypes.byref(data)) stdout = out.getvalue() print(stdout) print(ina) print(outa)
错误信息
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[51], line 3 1 # lets add this in a wrapper routine ----> 3 ctest.square_array2(ina,outa) File ~/WORK/PYTHONLIB/ctypesTEST/ctypesTEST3.py:46, in testClib.square_array2(self, ina, outa) 42 def square_array2(self,ina,outa): 44 n, = ina.shape ---> 46 data = Data(n,np.ctypeslib.as_ctypes(ina),np.ctypeslib.as_ctypes(outa)) 48 out = StringIO() 50 with pipes(stdout=out, stderr=STDOUT): TypeError: too many initializers
解决方案
问题根源在于testClib继承了Data类,而ctypes.Structure的子类被继承时,会破坏原结构体的初始化逻辑——子类的构造函数会干扰父类Data的实例化参数解析。
修复方法:移除testClib对Data类的继承,因为testClib是封装C库的工具类,不需要继承结构体类型。修改后的代码如下:
import ctypes import numpy as np from ctypes import CDLL, POINTER from ctypes import c_size_t, c_double, c_int from io import StringIO from wurlitzer import pipes, STDOUT class Data(ctypes.Structure): _fields_ = [("n", ctypes.c_int), ("ina", ctypes.POINTER(ctypes.c_double)), ("outa", ctypes.POINTER(ctypes.c_double))] class testClib: # 移除对Data的继承 def __init__(self): # 加载库 self.lib = CDLL("test.so") # 提前设置函数返回类型,避免重复设置 self.lib.square_array2.restype = None def square_array2(self,ina,outa): n, = ina.shape # 现在可正常实例化Data结构体 data = Data(n, np.ctypeslib.as_ctypes(ina), np.ctypeslib.as_ctypes(outa)) out = StringIO() with pipes(stdout=out, stderr=STDOUT): self.lib.square_array2(ctypes.byref(data)) stdout = out.getvalue() print(stdout) print("输入数组:", ina) print("输出数组:", outa)
调用示例
ctest = testClib() n=5 ina = np.linspace(1.0,5.0,n) outa = np.zeros(n,np.float64) ctest.square_array2(ina, outa)
修改后,结构体实例化不再出现参数数量错误,C函数可正常处理数组求平方逻辑。
内容的提问来源于stack exchange,提问作者Robert Smith
相关产品推荐
相关产品推荐

