拆分Cython pyx文件为pxd、pyx文件时出现编译错误
问题根因
两个编译错误的核心原因是pxd的类声明和pyx的类实现没有正确绑定:Cython没有识别到pyx中定义的Instrument类对应pxd里声明了C成员的版本,而是将其当作无预声明的普通Cython类处理,类的detectors、nbdet成员被默认推断为Python对象类型,才会出现类型不匹配错误:
- 给
free()传参时,编译器认为你传入的是Python对象,无法自动转为free需要的void* - 给
detectors赋值指针时,编译器认为你要把C指针塞给Python对象类型的属性,类型不合法
触发这个绑定失效的直接原因有两个:
- 你在pyx中重写类定义时重复写了继承关系
cdef class D11Instrument(Instrument):,相当于重新声明了一个新类,没有复用pxd里已经写好的成员声明 - pyx中多余cimport了不存在的
DetectorDescr、PixelInfo类型,后续也会触发导入错误,只是被前面的类型错误挡住了
修复步骤
1. 确认pxd文件内容
你现有的pxd逻辑基本正确,不需要大改,参考如下:
cdef struct s_detector: int size_x int size_y int offset int board_id_max ctypedef s_detector Detector cdef class Instrument: cdef int nbdet cdef Detector* detectors cdef class D11Instrument(Instrument): pass
2. 修改pyx文件
核心规则:同名pxd已经声明过的类继承关系、C成员,不需要在pyx里重复写,直接写类的方法实现即可;同时删除无效导入,补充空指针判断避免内存错误。修改后内容:
from libc.stdlib cimport free, malloc, NULL from instrument cimport Detector cdef class Instrument: def __dealloc__(self): if self.detectors != NULL: free(self.detectors) self.detectors = NULL cdef class D11Instrument: # 继承关系已经在pxd中声明,此处不需要重复写(Instrument) def __cinit__(self): self.nbdet = 3 self.detectors = <Detector*>malloc(self.nbdet*sizeof(Detector)) # 结构体按显式构造赋值兼容性更好,避免列表赋值的版本兼容问题 self.detectors[0] = s_detector(256, 192, 0, 6) self.detectors[1] = s_detector(32, 256, 49152, 7) self.detectors[2] = s_detector(32, 256, 57344, 8)
后续使用说明
- pxd和pyx同名同目录时,Cython会自动关联两者的声明,不需要额外编译配置
- 其他Cython模块要复用这些类型时,直接写
from instrument cimport Instrument, D11Instrument, Detector即可访问所有C级成员 - 手动malloc分配的堆内存必须在
__dealloc__中释放,补充非空判断可以避免类初始化失败时触发空指针崩溃
内容的提问来源于stack exchange,提问作者Eurydice
相关产品推荐
相关产品推荐

