Python abstractmethod con otra clase de base rompe la funcionalidad abstracta

Considere el siguiente ejemplo de código

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() 

Esto plantea correctamente el error:

 Traceback (most recent call last): File "/.../test.py", line 10, in  test = ABCtest_B() TypeError: Can't instantiate abstract class ABCtest_B with abstract methods foo 

Sin embargo, cuando la subclase de ABCtest también se hereda de un tipo incorporado como str o list no hay error y test.foo() llama al método abstracto:

 class ABCtest_C(ABCtest, str): pass >>> test = ABCtest_C() >>> test.foo() Traceback (most recent call last): File "", line 1, in  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 

Esto parece suceder cuando se hereda de cualquier clase definida en C, incluyendo itertools.chain y numpy.ndarray pero sigue numpy.ndarray errores correctamente con las clases definidas en python. ¿Por qué la implementación de uno de los tipos integrados rompería la funcionalidad de las clases abstractas?

Sorprendentemente, la prueba que evita la object.__new__ instancias de clases abstractas ocurre en el object.__new__ , en lugar de cualquier cosa definida por el propio módulo 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); 

(¿Casi?) Todos los tipos incorporados que no son object suministran un __new__ diferente que anula el object.__new__ y no llama al object.__new__ . Cuando se hereda de forma múltiple de un tipo incorporado que no es un object , se hereda su método __new__ , omitiendo la verificación del método abstracto.

No veo nada acerca de __new__ o la herencia múltiple de los tipos incorporados en la documentación de abc . La documentación podría utilizar la mejora aquí.

Parece un poco extraño que usaran una metaclase para la implementación de ABC, haciendo que sea un desastre usar otras metaclases con clases abstractas, y luego poner el control crucial en el código del lenguaje central que no tiene nada que ver con abc y se ejecuta para ambos Clases abstractas y no abstractas.

Hay un informe para este problema en el rastreador de problemas que ha estado languideciendo desde 2009.