2016-05-23 80 views
4

考虑下面的代码示例与其他基类蟒蛇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()调用抽象方法:

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中定义的类的错误。为什么要实现内置类型之一会破坏抽象类的功能?

+1

@DonkeyKong(或任何其他人没有得到它)​​方法'foo'应该被强制覆盖在一个子类中,通常(并且没有从'str'继承)实例化它会产生一个错误,但是当也从'str'继承,没有发生错误,抽象方法'test.foo'是一个有效的可调用方法。 –

+0

@ TadhgMcDonald-Jensen刚刚抓住了,谢谢:) – miradulo

+0

@Torxed'str'不是一个变量名。 – miradulo

回答

3

出人意料的是,测试类是否是抽象发生在object.__new__,而不是由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); 

(几乎?)所有内置类型不属于object供应一个不同的__new__,它会覆盖object.__new__而不会呼叫object.__new__。当您从非object内置类型多重继承时,您将继承其__new__方法,绕过抽象方法检查。

我在abc文档中看不到__new__或内置类型的多重继承。文档可以在这里使用增强。

看起来有点奇怪,他们会为ABC实现使用元类,使得使用其他元类与抽象类混乱,然后将核心语言代码中的关键检查与abc无关并为抽象类和非抽象类运行。