2009-07-07 9 views
1

Ich implementig ein Kompositum-Muster in this way:Python zusammengesetzte Muster Ausnahmebehandlung & Pylint

1) die "abstrakt" Komponente:

class Component(object): 
    """Basic Component Abstraction""" 
    def __init__(self, *args, **kw): 
     raise NotImplementedError("must be subclassed") 

    def status(self): 
     """Base Abstract method""" 
     raise NotImplementedError("must be implemented") 

2) ein Blatt:

class Leaf(Component): 
    """Basic atomic component 
    """ 
    def __init__(self, *args, **kw): 
     self.dict = {} 

    def status(self): 
     """Retrieves properties 
     """ 
     return self.dict 

Das Problem ist, dass pylint erzeugt natürlich diese Warnung:

Leaf.__init__: __init__ method from base class 'Component' is not called 

aber in meinem Blatt i für nicht nennen kann:

def __init__(self, *args, **kw): 
    Component.__init__(self, *args, **kw) 
    self.dict = {} 

ohne Erhöhung der Ausnahme.

Muss ich die pylint-Warnung ignorieren oder gibt es eine schlechte Codierung?

Antwort

4

Abstrakte Initialisierer sind eine schlechte Idee. Ihr Code könnte sich so weiterentwickeln, dass Sie eine Initialisierung in der Root-Komponente vornehmen möchten. Und selbst wenn Sie nicht warum die Implementierung des Initialisierers erfordern. Für einige Unterklassen wäre ein leerer Initialisierer eine akzeptable Wahl.

Wenn Sie keine Instanzen der Klasse Component wollen um, überprüfen Sie, dass in der Initialisierungsliste:

class Component(object): 
    def __init__(self, **kwargs): 
     assert type(self) != Component, "Component must not be instantiated directly" 

class Leaf(Component): 
    def __init__(self, some, args, **kwargs): 
     # regular initialization 
     Component.__init__(self, **kwargs) 
+0

Sie vorschlagen: "Abstrakte Initialisierer sind eine schlechte Idee. Ihr Code könnte sich entwickeln, so dass Sie einige Initialisierung in der Stammkomponente vornehmen möchten", aber ich bin in ein zusammengesetztes Muster und es muss solche Abstraktion haben. – DrFalk3n

+3

@ DrFalk3n. Lass uns nicht über die Java-Version des Musters fetischisieren. Java-Leute lieben ihre abstrakten Klassen. Python hat das einfach nicht. Wir sind alle Erwachsene hier, wir alle wissen, dass die abstrakte Klasse nicht funktioniert. Die Abstraktion von __init__, die NotImplemented auslöst, ist wirklich in Ordnung. Sie müssen die Java-/C++ - Dummheit in Python nicht erneut aufarbeiten. –

+0

Das zusammengesetzte Muster bedeutet nicht, dass Sie keinen gemeinsamen Initialisierungscode in der Basisklasse haben könnten. Was Sie vermeiden möchten, ist die Instanziierung der Basisklasse. Also check das mit if type (self) == Komponente: raise Exception ("Component darf nicht direkt instanziiert werden") –

1

Sie sicherstellen wollen, dass die Basisklasse Komponente nicht instanziiert. Dies ist eine noble Eigenschaft, die in anderen Programmiersprachen wie C++ üblich ist (wo Sie die Konstruktoren privat machen können, um direkte Verwendung zu verhindern).

Aber es wird nicht in Python unterstützt. Python unterstützt nicht alle Programmierungsbegriffe und ist auch "dynamischer". Die Initialisierung erfolgt also auf "pythonische" Weise und Ihre Vorstellung wird somit nicht unterstützt.

Python basiert viel mehr auf Vertrauen als andere Sprachen - so werden beispielsweise statische Variablen nicht unterstützt und private auch nur eingeschränkt.

Was Sie tun könnten (wenn Sie den Benutzern Ihres Moduls misstrauen) - Sie könnten die Basisklasse verbergen, indem Sie sie "_Component" nennen - machen Sie es zu einem internen Geheimnis. Aber das kann natürlich andere Probleme verursachen.

+0

+1: Geben Sie eine Dokumentation im Docstring ein. Wir sind alle Erwachsene hier. Wir haben nicht mit Java oder C++ zu kämpfen, wo wir gezwungen sind, dem Compiler mitzuteilen, wie man Code generiert. –

+0

@ S.Lott: :-) Du bist immer so relevant, danke – DrFalk3n

1

Nicht schlecht Codierung als solche, aber die __init__ der Komponente wird einfach nicht benötigt. Wenn Sie möchten, können Sie Pylint ignorieren, aber es ist eine bessere Idee, einfach die __init__ von Component zu entfernen.

Umarmen Sie die Dynamik!

+0

+1 wirklich guter Vorschlag zu mir – DrFalk3n

+0

Oder vielleicht entfernen Sie die gesamte Komponente Klasse. Welchen Wert fügt es hinzu? Sie können nur sicherstellen, dass alle Klassen die erwarteten Methoden haben – ierax

2

Ein weiterer Vorschlag, die Idee von Markus ergänzen:

Wenn Sie wirklich müssen, schlage ich vor, dass Sie verwenden __new __ und prüfen Sie für den Objekttyp angegeben. Wenn es „Komponente“ könnten Sie Ihre Ausnahme ausgelöst:

class Component(object): 
"""Basic Component Abstraction""" 

def __new__(objType, *args, **kwargs): 
    if objType == Component: 
     raise NotImplementedError("must be subclassed") 
    return object.__new__(type, *args, **kwargs) 

Wenn eine Unterklasse erstellt wird, wird objType sein = Komponente und alles wird in Ordnung sein!

+0

Alles klar, Typ (self) sollte auch gut funktionieren, da der Typ in __new__ vor __init__ zugeordnet ist. – Juergen

2

Umbenennen Ihrer Klasse Component zu AbstractComponent sollte helfen.Und stellen Sie in Ihrer Basisklasse keine __init__-Methode bereit, wenn sie nicht von Unterklassen aufgerufen werden soll.