带有另一个基类的python abstractmethod破坏了抽象功能 [英] python abstractmethod with another baseclass breaks abstract functionality

查看:115
本文介绍了带有另一个基类的python abstractmethod破坏了抽象功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下代码示例

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的子类也继承自诸如strlist的内置类型时,则没有错误,并且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.chainnumpy.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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆