带有另一个基类的python abstractmethod破坏了抽象功能
考虑下面的代码示例带有另一个基类的python abstractmethod破坏了抽象功能,python,multiple-inheritance,metaclass,abstract-methods,Python,Multiple Inheritance,Metaclass,Abstract Methods,考虑下面的代码示例 导入abc abc类测试(abc.abc): @抽象方法 def foo(self): raise RUNTIMERROR(“调用了抽象方法,这应该是不可能的”) ABCtest_B类(ABCtest): 通过 测试=ABCtest_B() 这会正确地引发错误: Traceback (most recent call last): File "/.../test.py", line 10, in <module> test = ABCtest_B()
导入abc
abc类测试(abc.abc):
@抽象方法
def foo(self):
raise RUNTIMERROR(“调用了抽象方法,这应该是不可能的”)
ABCtest_B类(ABCtest):
通过
测试=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
从C中定义的任何类(包括
itertools.chain
和numpy.ndarray
)继承时,似乎都会发生这种情况,但仍然正确地引发python中定义的类的错误。为什么实现一个内置类型会破坏抽象类的功能?令人惊讶的是,阻止实例化抽象类的测试发生在中,而不是由abc
模块本身定义的任何内容:
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);
(几乎是?)所有不是对象的内置类型
都提供一个不同的\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
来覆盖对象。uuuuuuuuuuuuuuuuuuuuuuuuuuuuu。当您从非对象
内置类型多次继承时,您将绕过抽象方法检查,继承其\uuuuuuuuu新方法
在abc
文档中,我没有看到任何关于\uuuu new\uuuu
或内置类型的多重继承的内容。文档可以在这里使用增强功能
看起来有点奇怪,他们会在ABC实现中使用一个元类,这使得在抽象类中使用其他元类变得一团糟,然后在与ABC
无关的核心语言代码中加入关键的检查,并为抽象类和非抽象类运行
自2009年以来,问题追踪者一直在关注这个问题。我问了一个类似的问题,根据s链接的错误报告,我提出了这个解决方法(基于以下人员的建议):
这会引发TypeError:无法实例化使用抽象方法bar、foo
派生的抽象类,这是原始行为。@DonkeyKong(或任何其他没有得到它的人)通常情况下,应该在子类中强制重写方法foo
(并且不从str
继承)实例化它会引发一个错误,但是当同时从str
初始化时,不会发生错误,并且抽象方法test.foo
是一个有效的可调用方法。@Tadhgcdonald Jensen刚刚流行起来,谢谢:)@Torxedstr
不是一个变量名。我刚刚意识到,谢谢你让我读了两遍@DonkeyKong:)哦,见鬼,如果有人知道这个消息来源,我会很高兴的。但这是规范的一部分吗?是否存在需要这种行为的情况?或者它是一个bug,或者只是一个没有被考虑的案例?
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);
from abc import ABC, abstractmethod
class Base(ABC):
@abstractmethod
def foo(self):
pass
@abstractmethod
def bar(self):
pass
def __new__(cls, *args, **kwargs):
abstractmethods = getattr(cls, '__abstractmethods__', None)
if abstractmethods:
msg = "Can't instantiate abstract class {name} with abstract method{suffix} {methods}"
suffix = 's' if len(abstractmethods) > 1 else ''
raise TypeError(msg.format(name=cls.__name__, suffix=suffix, methods=', '.join(abstractmethods)))
return super().__new__(cls, *args, **kwargs)
class Derived(Base, tuple):
pass
Derived()