python - 是否可以用 def 覆盖 cdef 方法?覆盖方法不会执行

标签 python cython

我正在实现一个类MyBinaryTissueClassifier,它具有父类(super class)TissueClassifier(我无法更改)。我试图重写 MyBinaryTissueClassifier 中的 TissueClassifier 中的方法之一,但我的实现没有被调用。父类(super class)函数是一个 cdef 函数,我正在使用 Python 并尝试使用 def 函数进行覆盖。这就是代码没有覆盖的原因吗?

TissueClassifier 类如下:

cdef class TissueClassifier:
    *code elided*
    cdef TissueClass check_point_c(self, double* point)
        pass

MyBinaryTissueClassifier 类应该覆盖它,它看起来像这样:

class MyBinaryTissueClassifier(TissueClassifier):
    *code elided*
    def check_point_c(self, point):
        *method body here*

我期望执行 MyBinaryTissueClassifier 的主体,但它从未被调用,BinaryTissueClassifier 的原始实例也没有被调用。看来 TissueClassifier check_point_c() 方法在调用 pass 后停止。

最佳答案

cdef函数只能被 cdef 覆盖(或 cpdef )派生类中的函数。这也是 cython 发出警告的原因:

warning: xxxxx.pyx:yy:z: Overriding cdef method with def method.

对于上面的例子。

通常的def - 功能非常灵活:不仅必须考虑多重继承,例如还必须考虑猴子修补。但这也意味着没有太多的优化空间:Cython 所能做的并不比使用 python 的机制多,即 PyObject_GetAttr / PyObject_GenericGetAttr + PyMethod_GET_SELF + PyMethod_GET_FUNCTION + 函数的调用。

这种灵 active 会导致巨大的开销,因此 cdef -函数通过使用不同的策略来避免它,这类似于C++-虚函数:

  • 每个 cdef -class 有一个虚拟表,其中存储了指向 cdef 函数的指针,每个函数都在其自己的槽中。
  • 这个 cdef 的每个对象-class 有一个指向该虚拟表的指针,因此可以在运行时解析对 cdef 函数的调用,并且该解析仅花费间接成本。
  • 子类可以覆盖 cdef - 通过将另一个函数指针放入虚拟表中的相应槽中来实现函数。

cdef 函数的典型调用如下所示:

%%cython

cdef class A:
    cdef doit(self):
        print(42)
    def call_doit(self):
        self.doit()

self.doit()导致以下 C 代码:

((struct __pyx_vtabstruct_XXX_A*)__pyx_v_self->__pyx_vtab)->doit(__pyx_v_self, 0);

对象的v表__pyx_v_self被解释为 cdef 类的 v 表 A (即使 self 不是 A 的实例,而是派生类的实例,此操作也可以正常工作)和槽 doit已执行。

上课时,比如说B源自A它可以覆盖插槽 doit ,所以 B 的 doit 版本被称为。插槽doit通过提供 cdef 的相应定义来覆盖-功能。

正如人们所看到的,当 def 时,有不同的机制在发挥作用。与 cdef 相比调用函数-功能。

因此cdef函数只能被其他 cdef 函数覆盖(而不是 def 函数)。更准确地说,还可以使用 cpdef - 覆盖方法 - 但在您的示例中它将不起作用,因为 cpdef函数不能有 double *参数,因为它们无法由 Cython 自动转换为 Python 对象,并且重写函数和被重写函数的签名必须匹配。

关于python - 是否可以用 def 覆盖 cdef 方法?覆盖方法不会执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56692187/

相关文章:

python - 如何引发包含 Unicode 字符串的异常?

python - 以编程方式获取和设置 QTreeview 中的事件行 (PyQt)

python - Pandas 将多索引的所有级别转换为另一种类型

python - Cython:无法将 Python 对象转换为结构

python - 如何使用 Cython 将外部 C 函数导入 IPython Notebook?

python - 尝试在下载的 Cython 目录中安装 Cython : no setup. py

python - Python中有一个简写的初始化程序吗?

python - 如何在仪表盘中旋转刻度盘?巧妙地使用 python

python - 在 Cython 中使用 lambda 函数时出错

python - 在 Python 中加快字符串与对象的配对