2017-06-28 5 views
3

Ich versuche, eine abstrakte Klasse A mit einem Konstruktor mit einem Standard-Verhalten zu erklären: alle Subklassen ein Mitglied self.n initialisieren müssen:Python: abstrakte Klasse __init__

from abc import ABCMeta 

class A(object): 
    __metaclass__ = ABCMeta 

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

Ich möchte jedoch nicht die A lassen Klasse instanziiert werden, denn es ist eine abstrakte Klasse. Das Problem ist, das ist eigentlich erlaubt:

a = A(3) 

Das erzeugt keine Fehler, wenn ich es erwarten würde.

Also: Wie kann ich eine nicht instanziierbare abstrakte Klasse definieren, während ich ein Standardverhalten für den Konstruktor definiere?

Antwort

4

Making the __init__ eine abstrakte Methode:

from abc import ABCMeta, abstractmethod 

class A(object): 
    __metaclass__ = ABCMeta 

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


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

hilft:

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

Python 3 Version:

from abc import ABCMeta, abstractmethod 

class A(object, metaclass=ABCMeta): 

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


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

funktioniert auch:

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

Das erzeugt keinen Fehler !! Instanziierung funktioniert gut – void

+0

Getestet mit Python 2.7. –

+0

Ja, ich benutze Python3 ... Warum ist es so? @ MikeMüller – void

1

A nicht so elegante Lösung kann das sein:

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

Nutzungs

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

Sie sollten die Methoden als abstrakt als auch mit dem @abc.abstractmethod Dekorateur definieren.

+0

Frage: Was ist der Punkt, eine Klasse als abstrakt zu definieren, wenn Sie explizit den Konstruktor als abstrakte Methode angeben müssen? (Ich betone nicht, dass alles eine abstrakte Klasse ist, ist nur eine nicht-instanziierbare Klasse) – dabadaba

+0

Ich denke, weil eine ABCMeta nicht genau eine abstrakte Klasse wie in anderen Sprachen ist. –

2

Sie können die Methode __new__ überschreiben, um eine direkte Instanziierung zu verhindern.

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) 

Ausgang:

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

Sie sollten 'args' und' kwargs' nicht zum Konstruktor 'object' weiterleiten. 'Objekt' nimmt keine Parameter an. –

+0

@Rawing [Wo heißt es so?] (Https://docs.python.org/2/reference/datamodel.html#object.__new__) Die an "__init__" übergebenen Argumente werden an "__new__" und "__call__" übergeben 'später. –

+0

Nun, versuchen Sie 'A (3)' und sagen Sie mir, ob es funktioniert ... Die an '__new__' übergebenen Argumente werden automatisch an' __init__' weitergeleitet, nachdem '__new__' eine Instanz zurückgibt. Sie möchten sie nicht an "object .__ new__" weiterleiten, da sie diese nicht akzeptiert. –