web-dev-qa-db-fra.com

Impossible d'instancier une classe abstraite ... avec des méthodes abstraites

Je travaille sur une sorte de lib, et pour une raison étrange, j'ai cette erreur. 

  • Ici est mon code. Bien sûr, @ abc.abstractmethod doit être décommenté
  • Ici sont mes tests

Désolé, je ne pouvais pas simplement copier et coller

Je suis allé sur la base que le code ci-dessous fonctionne 

test.py

import abc
import six

@six.add_metaclass(abc.ABCMeta)
class Base(object):

    @abc.abstractmethod
    def whatever(self,):
        raise NotImplementedError

class SubClass(Base):

    def __init__(self,):

        super(Base, self).__init__()
        self.whatever()

    def whatever(self,):
        print("whatever")

Dans le shell en python

>>> from test import *
>>> s = SubClass()
whatever

Pourquoi mon module roster rencontre-t-il cette erreur?

Can't instantiate abstract class Player with abstract methods _Base__json_builder, _Base__xml_builder

Merci d'avance 

15
josuebrunel

Votre problème vient du fait que vous avez défini les méthodes abstraites dans votre classe abstraite de base avec le préfixe __ (double soulignement). Cela fait que python fasse nom de mangling au moment de la définition des classes.

Les noms de la fonction passent de __json_builder à _Base__json_builder ou __xml_builder à _Base__xml_builder. Et c'est le nom que vous devez implémenter/écraser dans votre sous-classe.

Pour montrer ce comportement dans votre exemple -

>>> import abc
>>> import six
>>> @six.add_metaclass(abc.ABCMeta)
... class Base(object):
...     @abc.abstractmethod
...     def __whatever(self):
...             raise NotImplementedError
...
>>> class SubClass(Base):
...     def __init__(self):
...             super(Base, self).__init__()
...             self.__whatever()
...     def __whatever(self):
...             print("whatever")
...
>>> a = SubClass()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class SubClass with abstract methods _Base__whatever

Quand je change d'implémentation comme suit, ça marche

>>> class SubClass(Base):
...     def __init__(self):
...             super(Base, self).__init__()
...             self._Base__whatever()
...     def _Base__whatever(self):
...             print("whatever")
...
>>> a = SubClass()
whatever

Mais ceci est très fastidieux, pensez-y si vous voulez vraiment définir vos fonctions avec __ (double trait de soulignement). Vous pouvez en savoir plus sur le nom mangling ici .

20
Anand S Kumar

Cette erreur provient du code source de python. C'est pourquoi nous ne voyons pas la ligne d'exception réelle. 

PyErr_Format(PyExc_TypeError,        
             "Can't instantiate abstract class %s "
             "with abstract methods %U",
             type->tp_name,
             joined);

J'ai cloné le code source Python à partir de github. Cela provient du fichier typeobject.c.

1
Taras Vaskiv