2014-02-05 6 views
9

Ich verwende argparse Aktion, um verschiedene Daten zu einer Klasse hinzuzufügen. Ich möchte diese Aktion für den Standardwert verwenden, wenn dieses Argument nicht in der Befehlszeile angegeben wird. Ist das möglich? Danke!Ursache Pythons Argaparse zum Ausführen der Aktion für den Standard

+0

möglich Duplikat von [Python argparse: Standardwert oder angegebener Wert] (http://stackoverflow.com/questions/15301147/python-argparse-default-value-or-specified-value) –

+0

@LutzHorn, das ist nicht Ganz was ich brauche (glaube ich nicht), weil ich 1: argname = val und 2: eine beliebige argparse.Action speichern möchte, als ob --argname = val an der Kommandozeile gesetzt wurde –

Antwort

4

argparse verwendet nicht die action beim Anwenden der default. Es verwendet nur setattr. Es kann die type verwenden, wenn der Standardwert eine Zeichenfolge ist. Aber Sie können die action direkt aufrufen.

Hier verwende ich eine benutzerdefinierte Aktionsklasse aus der Dokumentation ausgeliehen. In der ersten parse_args passiert nichts. Dann erstelle ich eine neue namespace, und rufen Sie die Aktion auf den Standard. Dann übergebe ich diesen Namensraum an parse_args. Um das zu verstehen, müssen Sie es in eine interaktive Shell importieren und die Attribute des Namespace und der Aktion untersuchen.

# sample custom action from docs 
class FooAction(argparse.Action): 
    def __call__(self, parser, namespace, values, option_string=None): 
     print('Setting: %r %r %r' % (namespace, values, option_string)) 
     setattr(namespace, self.dest, 'action:'+values) 
p = argparse.ArgumentParser() 
a1 = p.add_argument('--foo', action=FooAction, default='default') 
print 'action:',a1 
print p.parse_args([]) 

ns = argparse.Namespace() 
a1(p, ns, a1.default, 'no string') # call action 
print p.parse_args([],ns) 
print p.parse_args(['--foo','1'],ns) 

die produziert:

action: FooAction(option_strings=['--foo'], dest='foo', nargs=None, const=None, default='default', type=None, choices=None, help=None, metavar=None) 
Namespace(foo='default') 
Setting: Namespace() 'default' 'no string' 
Namespace(foo='action:default') 
Setting: Namespace(foo='action:default') '1' '--foo' 
Namespace(foo='action:1') 

I den Ausgang zugeschnitten zu markieren, wenn die Aktion verwendet wird.


Hier ist eine Möglichkeit, eine besondere Aktion auf dem Argument durchführen, die nicht auf der Kommandozeile angegeben wird (oder mit einem Wert angegeben == auf die Standardeinstellung). Es ist eine Vereinfachung der in https://stackoverflow.com/a/24638908/901925 angegebenen Klasse.

class Parser1: 
    def __init__(self, desc): 
     self.parser = argparse.ArgumentParser(description=desc) 
     self.actions = [] 

    def milestone(self, help_='milestone for latest release.', default=None): 
     action = self.parser.add_argument('-m', '--milestone', help=help_, default=default) 
     self.actions.append(action) 
     return self 

    def parse(self): 
     args = self.parser.parse_args() 
     for a in self.actions: 
      if getattr(args, a.dest) == a.default: 
       print 'Please specify', a.dest 
       values = raw_input('>') 
       setattr(args, a.dest, values) 
     return args 

print Parser1('desc').milestone(default='PROMPT').parse() 

Die Abfrage erfolgt nach parse_args. Ich sehe keinen Grund wieder parse_args anzurufen.

+0

Danke. Dies ist sicherlich eine Möglichkeit, dies zu tun. (Außerdem bietet es gute Beispiele für andere Teile der Verwendung von Argarse). Ich habe den Körper von FooAction .__ call__ zu einer anderen Methode gezogen und manuell über Argumente wie deine a1 iteriert. Es ist wirklich eine Schande, dass es nicht eingebaut ist. –

+0

+1 - Ich habe es verwendet, um den Benutzer zu fragen, wenn keine Option übergeben wird - muss es wirklich so hacky sein? Keine Möglichkeit über die API eine Aktion auszuführen, wenn eine Option nicht gesetzt ist? –

+0

Ich würde warten, bis die gesamte Befehlszeile geparst ist, bevor ich den Benutzer nach weiteren Eingaben frage. Der einfachste Weg, dies zu tun, ist 'args = parse_args ...', und dann meine Aktion auf den Inhalt von 'args. Kein Versuch, etwas zu tun "das erste Mal, dass ich keine Option finde"! – hpaulj

0

Ich brauchte den Benutzer aufzufordern, wenn keine Option angegeben wurde - das ist, wie ich es tat:

class _PromptUserAction(argparse.Action): 

    def __call__(self, parser, namespace, values, option_string=None): 
     if values == self.default: 
      print 'Please specify', self.dest 
      values = raw_input('>') 
     setattr(namespace, self.dest, values) 

class Parser: 
    def __init__(self, desc, add_h=True): 
     self.parser = argparse.ArgumentParser(description=desc, add_help=add_h, 
         formatter_class=argparse.ArgumentDefaultsHelpFormatter) 
     #actions to be run on options if not specified (using default to check) 
     self.actions = [] 

    @staticmethod 
    def new(description, add_help=True): 
     return Parser(description, add_help) 

    # ... 

    def milestone(self, help_='Specify the milestone for latest release.'): 
     action = self.parser.add_argument('-m', '--milestone', 
              dest='milestone', 
              action=_PromptUserAction, 
              default='PROMPT', # needed I think 
              type=str, 
              help=help_) 
     self.actions.append(action) 
     return self 

    def parse(self): 
     """ 
     Return an object which can be used to get the arguments as in: 
      parser_instance.parse().milestone 

     :return: ArgumentParser 
     """ 
     args = self.parser.parse_args() 
     # see: http://stackoverflow.com/a/21588198/281545 
     dic = vars(args) 
     ns = argparse.Namespace() 
     for a in self.actions: 
      if dic[a.dest] == a.default: 
       a(self.parser, ns, a.default) # call action 
     # duh - can I avoid it ? 
     import sys 
     return self.parser.parse_args(sys.argv[1:],ns) 

Ich bin interessiert, wenn dies irgendwie ohne getan werden kann, um die args (der import sys Teil) zu Analysepunkten . Vielleicht einige Konstruktoroptionen für argparse.Action?

+0

Ich habe eine vereinfachte Version deines Beispiels zu meiner Antwort hinzugefügt. Ist das die Funktionalität, die Sie suchen? – hpaulj

+0

@hpaulj: wie Pythonic - danke - ich bestand darauf zu versuchen, "meine Aktion zu laufen" - wird es irgendwann verwenden und posten zurück, wenn ich über irgendwelche Seltsamkeit stoße –

Verwandte Themen