2016-05-04 15 views
0

Ich versuche herauszufinden, die beste Möglichkeit, Sub/Superklassen in Python3 zu initialisieren. Sowohl die Basis als auch die Unterklassen benötigen ein halbes Dutzend Parameter, die alle von Befehlszeilenargumenten analysiert werden.Best Practices für die Übergabe von Initialisierungsargumenten an Superklassen?

Der offensichtliche Weg, dies zu implementieren ist auf einmal alle Argumente zu analysieren, und übergeben sie alle in:

class Base: 
    def __init__(self, base_arg1, base_arg2, base_arg3): 

class Sub(Base): 
    def __init__(self, sub_arg1, sub_arg2, sub_arg3, 
        base_arg1, base_arg2, base_arg3): 
    super().__init__(self, base_arg1, base_arg2, base_arg3) 

main(): 
    # parse args here 
    options = parser.parse_args() 

    obj = Sub(options.sub_arg1, options.sub_arg2, options.sub_arg3, 
       options.base_arg1, options.base_arg2, options.base_arg3) 

Wenn ich eine Sub-Unterklasse haben (was ich will), die Dinge wirklich haarig in Begriffe der Liste von Argumenten, die durch sukzessive super() weitergegeben werden. init() Anrufe.

Aber es fällt mir ein, dass argparse.parse_known_args() einen anderen Weg bietet: ich jede Unterklasse, die Argumente analysieren, haben könnte, es braucht/erkennt und den Rest der Argumente auf die Hierarchie übergeben:

class Base: 
    def __init__(self, args): 
     base_options = base_parser.parse_known_args(args) 

class Sub(Base): 
    def __init__(self, args): 
     (sub_options, other_args) = sub_parser.parse_known_args(args) 
     super().__init__(self, other_args) 

main(): 
    obj = Sub(sys.argv) 

Dies scheint aus API-Sicht sauberer zu sein. Aber ich kann mir vorstellen, dass es gegen einige Grundsätze der Art, wie Dinge in Python getan werden, verstößt und aus allen möglichen Gründen eine schlechte Idee ist. Meine Suche im Internet hat keine Beispiele gezeigt - könnte der mächtige und allwissende Verstand von Stack Overflow mir helfen, den richtigen Weg zu verstehen, dies zu tun?

Antwort

0

Schauen Sie sich den Code argparse.py an. Ein ArgumentParser ist eine Unterklasse eines _ActionsContainer. Alle actions sind Unterklassen von Action.

Wenn Sie anrufen

parser.add_argument('foo', action='store_action', ...) 

die Parameter übergeben werden, meist als *args und **kwargs zu _StoreAction, was wiederum sie geht auf seiner supper (nach ein paar Standardwerte einstellen, etc).

Als ein Modul, das importiert werden soll, und nie als ein Stand entlang Skript ausgeführt wird, hat es keinen if __name__.... Block. Aber oft werde ich einen solchen Block hinzufügen, um den Testcode aufzurufen. Das ist der Ort, an den der Kommandozeilen-Parser gestellt oder zumindest aufgerufen werden kann. Wenn es in einer Funktion im Text definiert ist, sollte es normalerweise nicht aufgerufen werden, wenn das Modul importiert wird.

Im Allgemeinen ist argparse ein Skript-Tool und sollte nicht Teil einer Klassendefinition sein - es sei denn, Sie sind eine Unterklasse ArgumentParser, um einige neue Funktionen hinzuzufügen.

Sie möchten vielleicht auch https://pypi.python.org/pypi/plac betrachten. Dieses Paket bietet eine andere Schnittstelle zu argparse und ist ein gutes Beispiel für die Unterklasse dieses Parsers.

0

Danke hpaulj! Ich denke, Ihre Antwort hat mir geholfen, einen noch einfacheren Weg zu finden. Ich kann alle Optionen auf der obersten Ebene analysieren, dann übergeben Sie einfach den Options-Namespace in und lassen Sie jede Unterklasse diejenigen herausziehen, die sie benötigt. Art der Gesicht-Handfläche einfach, im Vergleich zu den anderen Ansätzen:

class Base: 
    def __init__(self, options): 
     base_arg1 = options.base_arg1 
     base_arg2 = options.base_arg2 

class Sub(Base): 
    def __init__(self, options): 
     super().__init__(self, options) # initialize base class 
     sub_arg1 = options.sub_arg1 
     sub_arg2 = options.sub_arg2 

main(): 
    options = parser.parse_args() 
    obj = Sub(options)