让C扩展类继承Python类

3
我有一个Python类AbstractFoo,它使用@abc.abstractmethod定义了2个抽象方法。为了提高性能,大部分工作都是在C中实现的Python扩展类CFoo中完成的,因此我想要做的是从AbstractFoo继承该扩展类。
然而,我没有找到一种方法来做到这一点,于是采用了不同的方法:在C中将其实现为“普通”类,并有一个class ConcreteFoo(AbstractFoo, CFoo),它从抽象Python和扩展类中继承。
然而,现在ABC的“保护”没有起作用:即使缺少方法,也没有抛出错误。我在https://dev59.com/AmIj5IYBdhLWcg3wRjSr#20440259中找到了解决方案,并添加了一个新的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)会显示它抱怨的方法。

是否有一种方式可以拥有一个经过ABC检查的AbstractFoo子类,其中方法是用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)

我认为__abstractmethods__是在由ABCMeta创建类型时设置的。因此,当你定义类型ConcreteFoo而不是PyType_Type时,你需要确保调用这个元类。不幸的是,你没有展示这一部分的代码... - undefined
我不确定你指的是哪段代码。未显示的代码基本上是你使用的基本样板代码。我在上面添加了ConcreteFoo的定义和AbstractFoo的重要部分。 - undefined
啊 - 我有点误解,以为你是在C语言中声明ConcreteFoo(例如使用PyObject_Call(PyType_Type,...))。这样做确实更清晰明了。 - undefined
register作为一个抽象方法名是一个危险的选择,因为它与abc库中对register名称的使用存在冲突。 - undefined
1个回答

2
你需要将CFoo作为第一个基类。这与C-API没有太大关系,也适用于纯Python版本:如果你定义了
class CFoo:
    def register(self):
        return "CFoo.register"

那么

class ConcreteFoo(AbstractFoo, CFoo):

失败了,但是。
class ConcreteFoo(CFoo, AbstractFoo):

工作。

这在__mro__方面是有意义的,您可以通过使register不是抽象方法来测试这一点。您会发现首个基类的方法被优先使用。当第一个基类是AbstractFoo时,这是找到的第一个抽象方法,因此它会失败。


这是正确的,也能正常工作,谢谢。我觉得这有点违反直觉,因为我本来期望继承是从左到右进行的。为了完整起见:你有官方文档的链接吗? - undefined
也许可以使用https://www.python.org/download/releases/2.3/mro/(尽管显然它会变得非常详细)。也许思考它的方式是,所有基类中的所有方法仍然存在,并且从左到右搜索以找到适合的方法(而不是“通过添加新的基类来覆盖方法”,我认为这是你的假设)。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接