2017-06-28 1 views
3

Je suis en train de déclarer une classe abstraite A avec un constructeur avec un comportement par défaut: toutes les sous-classes doivent initialiser un membre self.n:Python: classe abstraite __init__

from abc import ABCMeta 

class A(object): 
    __metaclass__ = ABCMeta 

    def __init__(self, n): 
     self.n = n 

Cependant, je ne veux pas laisser le A class être instancié parce que, bien, c'est une classe abstraite. Le problème est, cela est réellement autorisé:

a = A(3) 

Cela ne produit pas d'erreurs, quand je m'attendais à ce qu'il devrait. Donc, comment puis-je définir une classe abstraite non-instanciable tout en définissant un comportement par défaut pour le constructeur?

Répondre

4

Faire la __init__ une méthode abstraite:

from abc import ABCMeta, abstractmethod 

class A(object): 
    __metaclass__ = ABCMeta 

    @abstractmethod 
    def __init__(self, n): 
     self.n = n 


if __name__ == '__main__': 
    a = A(3) 

aide:

TypeError: Can't instantiate abstract class A with abstract methods __init__ 

Python version 3:

from abc import ABCMeta, abstractmethod 

class A(object, metaclass=ABCMeta): 

    @abstractmethod 
    def __init__(self, n): 
     self.n = n 


if __name__ == '__main__': 
    a = A(3) 

fonctionne aussi bien:

TypeError: Can't instantiate abstract class A with abstract methods __init__ 
+0

Cela ne produit aucune erreur !! instanciation fonctionne bien – void

+0

Testé avec Python 2.7. –

+0

Ouais j'utilise python3 ... Pourquoi est-ce que c'est? @ MikeMüller – void

1

Une solution élégante pas peut être ceci:

class A(object): 
    def __init__(self, n): 
    if self.__class__ == A: 
     raise Exception('I am abstract!') 
    self.n = n 

Utilisation

class B(A): 
    pass 
a = A(1) # Will throw exception 
b = B(1) # Works fine as expected. 
2

Vous devez définir les méthodes aussi abstrait aussi bien avec le décorateur @abc.abstractmethod.

+0

question: quel est le point de définir une classe comme abstraite si vous avez besoin de spécifier explicitement le constructeur comme une méthode abstraite? (notez que je ne sous-entends pas que toute classe abstraite est, est juste une classe non-instanciable) – dabadaba

+0

Je suppose que parce qu'une ABCMeta n'est pas exactement une classe abstraite comme dans d'autres langages. –

2

Vous pouvez remplacer la méthode __new__ pour empêcher l'instanciation directe.

class A(object): 
    __metaclass__ = ABCMeta 

    def __new__(cls, *args, **kwargs): 
     if cls is A: 
      raise TypeError(
       "TypeError: Can't instantiate abstract class {name} directly".format(name=cls.__name__) 
      ) 
     return object.__new__(cls) 

Sortie:

>>> A() 
Traceback (most recent call last): 
    File "<ipython-input-8-3cd318a12eea>", line 1, in <module> 
    A() 
    File "/Users/ashwini/py/so.py", line 11, in __new__ 
    "TypeError: Can't instantiate abstract class {name} directly".format(name=cls.__name__) 
TypeError: TypeError: Can't instantiate abstract class A directly 
+0

Vous n'êtes pas censé transmettre 'args' et' kwargs' au constructeur 'object'. 'object' ne prend aucun paramètre. –

+0

@Rawing [Où cela se trouve-t-il?] (Https://docs.python.org/2/reference/datamodel.html#object.__new__) Les arguments passés à '__init__' sont passés à' __new__' et '__call__ Plus tard. –

+0

Eh bien alors essayez 'A (3)' et dites moi si cela fonctionne ... Les arguments passés à '__new__' sont automatiquement transmis à' __init__' après que '__new__' renvoie une instance. Vous ne voulez pas les transférer à 'object .__ new__', car il ne les accepte pas. –