带有另一个基类的python abstractmethod破坏了抽象功能 [英] python abstractmethod with another baseclass breaks abstract functionality
问题描述
考虑以下代码示例
import abc
class ABCtest(abc.ABC):
@abc.abstractmethod
def foo(self):
raise RuntimeError("Abstract method was called, this should be impossible")
class ABCtest_B(ABCtest):
pass
test = ABCtest_B()
这正确地引发了错误:
Traceback (most recent call last):
File "/.../test.py", line 10, in <module>
test = ABCtest_B()
TypeError: Can't instantiate abstract class ABCtest_B with abstract methods foo
但是,当ABCtest
的子类也继承自诸如str
或list
的内置类型时,则没有错误,并且test.foo()
调用了抽象方法:
However when the subclass of ABCtest
also inherits from a built in type like str
or list
there is no error and test.foo()
calls the abstract method:
class ABCtest_C(ABCtest, str):
pass
>>> test = ABCtest_C()
>>> test.foo()
Traceback (most recent call last):
File "<pyshell#0>", line 1, in <module>
test.foo()
File "/.../test.py", line 5, in foo
raise RuntimeError("Abstract method was called, this should be impossible")
RuntimeError: Abstract method was called, this should be impossible
从C中定义的任何类(包括itertools.chain
和numpy.ndarray
)继承时,似乎都发生了这种情况,但仍然正确地引发了python中定义的类的错误.为什么实现内置类型之一会破坏抽象类的功能?
This seems to happen when inheriting from any class defined in C including itertools.chain
and numpy.ndarray
but still correctly raises errors with classes defined in python. Why would implementing one of a built in types break the functionality of abstract classes?
推荐答案
Surprisingly, the test that prevents instantiating abstract classes happens in object.__new__
, rather than anything defined by the abc
module itself:
static PyObject *
object_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
...
if (type->tp_flags & Py_TPFLAGS_IS_ABSTRACT) {
...
PyErr_Format(PyExc_TypeError,
"Can't instantiate abstract class %s "
"with abstract methods %U",
type->tp_name,
joined);
(几乎?)不是object
的所有内置类型都提供一个不同的__new__
,这些__new__
会覆盖object.__new__
并且不会调用object.__new__
.从非object
内置类型进行多继承时,您将绕过抽象方法check继承其__new__
方法.
(Almost?) all built-in types that aren't object
supply a different __new__
that overrides object.__new__
and does not call object.__new__
. When you multiple-inherit from a non-object
built-in type, you inherit its __new__
method, bypassing the abstract method check.
在abc
文档中,我看不到任何有关__new__
或从内置类型的多重继承的信息.该文档可以在此处使用增强功能.
I don't see anything about __new__
or multiple inheritance from built-in types in the abc
documentation. The documentation could use enhancement here.
他们为ABC实现使用元类似乎有点奇怪,将其他元类与抽象类一起使用却变得一团糟,然后将关键的检查放在与
It seems kind of strange that they'd use a metaclass for the ABC implementation, making it a mess to use other metaclasses with abstract classes, and then put the crucial check in core language code that has nothing to do with abc
and runs for both abstract and non-abstract classes.
自2009年以来一直处于疲软状态的问题跟踪器上有针对此问题的报告.
There's a report for this issue on the issue tracker that's been languishing since 2009.
这篇关于带有另一个基类的python abstractmethod破坏了抽象功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!