5 Stimmen

Konstruktor-Spezialisierung in Python

Klassenhierarchien und Konstruktoren sind miteinander verbunden. Die Parameter einer untergeordneten Klasse müssen an ihre übergeordnete Klasse übergeben werden.

In Python erhalten wir also etwas wie dieses:

class Parent(object):
    def __init__(self, a, b, c, ka=None, kb=None, kc=None):
        # do something with a, b, c, ka, kb, kc

class Child(Parent):
    def __init__(self, a, b, c, d, e, f, ka=None, kb=None, kc=None, kd=None, ke=None, kf=None):
        super(Child, self).__init__(a, b, c, ka=ka, kb=kb, kc=kc)
        # do something with d, e, f, kd, ke, kf

Stellen Sie sich dies mit einem Dutzend untergeordneter Klassen und vielen Parametern vor. Das Hinzufügen neuer Parameter wird sehr mühsam.

Natürlich kann man auf benannte Parameter ganz verzichten und *args und **kwargs verwenden, aber das macht die Methodendeklarationen zweideutig.

Gibt es ein Muster für einen eleganten Umgang mit diesem in Python (2.6)?

Mit "elegant" meine ich, dass ich die Anzahl der Parameter reduzieren möchte. a, b, c, ka, kb, kc erscheinen alle drei Mal: im Child-Konstruktor, im super()-Aufruf an Parent und im Parent-Konstruktor.

Im Idealfall möchte ich die Parameter für Parents init einmal, und in Child's init nur die zusätzlichen Parameter angeben.

Ich würde gerne etwas in dieser Richtung machen:

class Parent(object):
    def __init__(self, a, b, c, ka=None, kb=None, kc=None):
        print 'Parent: ', a, b, c, ka, kb, kc

class Child(Parent):
    def __init__(self, d, e, f, kd='d', ke='e', kf='f', *args, **kwargs):
        super(Child, self).__init__(*args, **kwargs)
        print 'Child: ', d, e, f, kd, ke, kf

x = Child(1, 2, 3, 4, 5, 6, ka='a', kb='b', kc='c', kd='d', ke='e', kf='f')

Das funktioniert leider nicht, da 4, 5, 6 schließlich kd, ke, kf zugeordnet werden.

Gibt es ein elegantes Python-Muster für das Erreichen der oben genannten?

8voto

S.Lott Punkte 371691

"Ein Dutzend untergeordneter Klassen und viele Parameter" klingt nach einem Problem, unabhängig von der Benennung der Parameter.

Ich vermute, dass man mit ein wenig Refactoring einige Strategie Objekte, die diese Hierarchie vereinfachen und die superkomplexen Konstruktoren überflüssig machen würden.

3voto

Adam Punkte 6589

Nun, die einzige Lösung, die ich sehen konnte, ist die Verwendung einer Mischung aus aufgelisteten Variablen sowie *args und **kwargs als solche:

class Parent(object):
    def __init__(self, a, b, c, ka=None, kb=None, kc=None):
        pass

class Child(Parent):
    def __init__(self, d, e, f, *args, kd=None, ke=None, kf=None, **kwargs):
        Parent.__init__(self, *args, **kwargs)
        pass

Auf diese Weise können Sie sehen, welche Parameter für die einzelnen Klassen erforderlich sind, ohne sie erneut eingeben zu müssen.

Eine Sache zu beachten ist, dass Sie Ihre gewünschte Reihenfolge (a, b, c, d, e, f) verlieren, da es (d, e, f, a, b, c) wird. Ich bin nicht sicher, ob es eine Möglichkeit gibt, die *args vor den anderen nicht benannten Parametern zu haben.

1voto

maccullt Punkte 2719

Ich versuche, die Parameter in eigenen Objekten zu gruppieren, z.B. statt der Übergabe von sourceDirectory, targetDirectory, temporaryDirectory, serverName, serverPort, würde ich ein DirectoryContext und ServerContext Objekte.

Wenn die Kontextobjekte anfangen, mehr Verhalten oder Logik zu haben, könnte dies zu den Strategieobjekten führen, die in aquí .

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X