【发布时间】:2020-05-22 17:13:12
【问题描述】:
我有一个 Python 类 AbstractFoo,它使用 @abc.abstractmethod 定义 2 个抽象方法。
为了提高性能,大部分工作都是在 C 中作为 Python 扩展类 CFoo 实现的,所以我想做的是从 AbstractFoo 继承该扩展类。
但是我还没有找到一种方法来做到这一点并采取了不同的路线:将其实现为 C 中的“普通”类,并拥有一个继承自抽象 Python 和扩展类的class ConcreteFoo(AbstractFoo, CFoo)。
但是现在 ABC 的“保护”没有发挥作用:即使缺少方法也不会引发错误。我在https://stackoverflow.com/a/20440259/1930508 中找到了一个解决方案,并添加了一个新的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 检查子类在 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。不幸的是,您没有显示这段代码... -
我不确定你的意思是什么代码。未显示的代码几乎是您使用的基本样板代码。我在上面添加了
ConcreteFoo的定义和AbstractFoo的重要部分 -
啊 - 我有点误解,以为你在 C 中声明
ConcreteFoo(例如PyObject_Call(PyType_Type,...)这确实让事情更清楚 -
register是抽象方法名称的危险选择,因为它与abc's own use of the nameregister冲突。
标签: python python-c-api