让 C 扩展 class 继承自 Python class

Have C extension class inherit from Python class

我有一个 Python class AbstractFoo 它使用 @abc.abstractmethod 来定义 2 个抽象方法。

为了提高性能,大部分工作是在 C 中作为 Python 扩展 class CFoo 实现的,所以我想做的是继承该扩展 class 来自 AbstractFoo.

但是我还没有找到一种方法来做到这一点,而是走了一条不同的路:在 C 中将其实现为 "normal" class 并有一个 class ConcreteFoo(AbstractFoo, CFoo) 继承自摘要 Python 和扩展 class.

但是现在 ABC 的 "protection" 没有启动:即使缺少方法也没有抛出错误。我在 中找到了一个解决方案并添加了一个新的 new 方法而不是 PyType_GenericNew (暂时忽略 empty_* 部分的引用计数):

static PyObject* CFoo_new(PyTypeObject* type, PyObject*, PyObject*)
{
    auto* empty_tuple(PyTuple_New(0));
    if (!empty_tuple)
        return nullptr;
    auto* empty_dict(PyDict_New());
    if (!empty_dict)
        return nullptr;
    return PyBaseObject_Type.tp_new(type, empty_tuple.get(), empty_dict.get());
}

但现在 ABC 检查总是触发:TypeError: Can't instantiate abstract class ConcreteFoo with abstract methods ...
但是检查 dir(ConcreteFoo) 会显示它抱怨的方法。

有没有办法让我的 AbstractFoo 的 ABC 检查子 class 在 C 中实现方法?

编辑:更多代码:

class AbstractFoo(abc.ABC):
    @abc.abstractmethod
    def register(self):
        pass
    # ...

#...

class ConcreteFoo(AbstractFoo, CFoo):
    def __init__(self, arg):
        AbstractFoo.__init__(self)
        CFoo.__init__(self, arg)

你必须让CFoo成为第一垒class。这与 C-API 关系不大,也适用于纯 Python 版本:如果您定义

class CFoo:
    def register(self):
        return "CFoo.register"

然后

class ConcreteFoo(AbstractFoo, CFoo):

失败,但是

class ConcreteFoo(CFoo, AbstractFoo):

有效。

这在 __mro__ 方面是有意义的,您可以通过使 register 不是抽象方法来测试它。你会发现优先使用第一个碱基 class 的方法。当第一个基 class 是 AbstractFoo 时,这个 一个最先找到的抽象方法,所以它失败了。