在构造函数中使用继承和错误参数名称时出现 Cython 段错误

问题描述 投票:0回答:1

我在 Cython 中遇到了一系列与继承相关的奇怪分段错误。

以下最小示例说明了这一点:

缓冲区.pxd

from libc.stdint cimport uint16_t, uint32_t
from cpython.mem cimport PyMem_RawCalloc,PyMem_RawFree

cdef class PixelBase:
    pass
        
cdef class PixelBuffer(PixelBase):
    cdef:
        uint16_t* value

    cdef void allocate(self, uint32_t len)
    cdef void deallocate(self)

缓冲区.pyx

cdef class PixelBase:
    def __cinit__(self, uint32_t buf_len = 100):
        pass

    def __init__(self, uint32_t buf_len  = 100):
        pass


cdef class PixelBuffer(PixelBase):

    def __cinit__(self, uint32_t buf_len = 100):
        self.allocate(buf_len)

    def __init__(self, uint32_t buf_len = 100):
        super().__init__(buf_len)

    def __dealloc__(self):
        self.deallocate()

    cdef void allocate(self, uint32_t buf_len): 
        self.value = <uint16_t*> PyMem_RawCalloc(1, buf_len * sizeof(uint16_t))

    cdef void deallocate(self): 
        PyMem_RawFree(self.value)

如果我对其进行cython化

cythonize -i buffer.pyx

并使用错误参数名称

运行测试
from src.buffer import PixelBuffer

buffer = PixelBuffer(wrong_parameter_name=10)

然后它会出现段错误(不会引发异常)。删除继承(PixelBuffer 不是 PixelBase 的子类)后,会抛出适当的异常。

我遇到过与继承和使用属性相关的类似段错误问题,我试图弄清楚我的继承实现是否从根本上是错误的。

有人可以评论我从 PixelBase 继承 PixelBuffer 的方式是否存在根本性错误吗?


Python 版本 3.11.4,Cython 版本 3.0.2

python cython
1个回答
0
投票

当超类的

__cinit__
中引发异常时,子类的
__dealloc__
将被执行。如果子类的
__dealloc__
中调用了实例C方法,则会出现错误,因为C方法同时没有正确设置。 (见下文)

%%cython

cdef class PixelBase:
    def __cinit__(self, int buf_len = 100):
        raise Exception()

cdef class PixelBuffer(PixelBase):

    def __dealloc__(self):
        self.abcd() #crashed
        
    cdef void abcd(self):
        pass

此外,不建议定义在 cdef 类的

__init__
__cinit__
__dealloc__
__del__
中专门调用的实例 C 方法,因为这提供的性能增益很少或没有。一段可重用的代码可以在类外部的 cdef 方法中定义,或者在 cdef 类内部由
@staticmethod
包装,这对于尝试加速时的大多数目的来说已经足够了。

%%cython

cdef class PixelBase:
    def __cinit__(self, int buf_len = 100):
        raise Exception()

cdef class PixelBuffer(PixelBase):
    
    def __dealloc__(self):
        PixelBuffer.abcd(self) #no problem, the exception will be raised as expected

    @staticmethod
    cdef void abcd(PixelBuffer a):
        pass
© www.soinside.com 2019 - 2024. All rights reserved.