1028 Stimmen

Boolean-Werte mit argparse analysieren

Ich möchte argparse verwenden, um boolean Befehlszeilenargumente zu parsen, die als "--foo True" oder "--foo False" geschrieben sind. Zum Beispiel:

my_program --my_boolean_flag False

Der folgende Testcode tut jedoch nicht, was ich möchte:

import argparse
parser = argparse.ArgumentParser(description="Mein Parser")
parser.add_argument("--my_bool", type=bool)
cmd_line = ["--my_bool", "False"]
parsed_args = parser.parse(cmd_line)

Leider ergibt parsed_args.my_bool True. Dies ist auch der Fall, wenn ich cmd_line zu ["--my_bool", ""] ändere, was überraschend ist, da bool("") zu False ausgewertet wird.

Wie kann ich argparse dazu bringen, "False", "F" und deren Kleinschreibungsvarianten als False zu parsen?

41voto

hpaulj Punkte 200871

Es scheint einige Verwirrung darüber zu geben, was type=bool und type='bool' bedeuten könnten. Sollte eines (oder beide) bedeuten 'führe die Funktion bool() aus' oder 'gib einen booleschen Wert zurück'? So wie es ist, bedeutet type='bool' nichts. add_argument gibt einen Fehler 'bool' is not callable aus, genauso wie wenn du type='foobar' oder type='int' verwenden würdest.

Aber argparse hat ein Register, das es dir ermöglicht, Schlüsselwörter wie dieses zu definieren. Es wird hauptsächlich für action verwendet, z.B. `action='store_true'. Du kannst die registrierten Schlüsselwörter mit folgendem Befehl anzeigen:

parser._registries

was ein Wörterbuch anzeigt

{'action': {None: argparse._StoreAction,
  'append': argparse._AppendAction,
  'append_const': argparse._AppendConstAction,
...
 'type': {None: }}

Es gibt viele Aktionen, die definiert sind, aber nur ein Typ, der Standardtyp, argparse.identity.

Dieser Code definiert ein 'bool' Schlüsselwort:

def str2bool(v):
  #susendbergs Funktion
  return v.lower() in ("yes", "true", "t", "1")
p = argparse.ArgumentParser()
p.register('type','bool',str2bool) # füge Typ-Schlüsselwort zu Registrierungen hinzu
p.add_argument('-b',type='bool')  # benutze nicht 'type=bool'
# p.add_argument('-b',type=str2bool) # funktioniert genauso gut
p.parse_args('-b false'.split())
Namespace(b=False)

parser.register() ist nicht dokumentiert, aber auch nicht verborgen. Im Großen und Ganzen muss der Programmierer nicht darüber Bescheid wissen, da type und action Funktionen und Klassenwerte übernehmen. Es gibt viele Beispiele auf stackoverflow, wie man benutzerdefinierte Werte für beide definiert.


Falls es nicht offensichtlich aus der vorherigen Diskussion ist, bedeutet bool() nicht 'analysiere einen String'. Aus der Python-Dokumentation:

bool(x): Konvertiere einen Wert zu einem Boolean, unter Verwendung des standardmäßigen Wahrheitstests.

Vergleiche dies mit

int(x): Konvertiere eine Zahl oder einen String x in eine Ganzzahl.

34voto

Akash Desarda Punkte 679

Einfachste und korrekteste Methode ist:

from distutils.util import strtobool

parser.add_argument('--feature', dest='feature', 
                    type=lambda x: bool(strtobool(x)))

Beachten Sie, dass Wahrheitswerte y, yes, t, true, on und 1 sind; falsche Werte sind n, no, f, false, off und 0. Wirft ValueError, wenn val etwas anderes ist.

29voto

dl.meteo Punkte 1614

Ein ziemlich ähnlicher Weg ist es, folgendes zu verwenden:

feature.add_argument('--feature',action='store_true')

und wenn Sie das Argument --feature in Ihrem Befehl setzen

 command --feature

wird das Argument True sein, wenn Sie den Typ --feature nicht setzen, ist das Argument standardmäßig immer False!

21voto

susundberg Punkte 600

Ich habe nach dem gleichen Problem gesucht, und meiner Meinung nach ist die hübsche Lösung :

def str2bool(v):
  return v.lower() in ("yes", "true", "t", "1")

und das verwenden, um den String in ein boolesches Wert umzuwandeln, wie oben vorgeschlagen.

15voto

Stumpy Joe Pete Punkte 360

Dies funktioniert für alles, was ich erwarte:

add_boolean_argument(parser, 'foo', default=True)
parser.parse_args([])                   # Was auch immer der Standardwert war
parser.parse_args(['--foo'])            # True
parser.parse_args(['--nofoo'])          # False
parser.parse_args(['--foo=true'])       # True
parser.parse_args(['--foo=false'])      # False
parser.parse_args(['--foo', '--nofoo']) # Fehler

Der Code:

def _str_to_bool(s):
    """Wandelt einen String in einen bool um (im argparse-Kontext)."""
    if s.lower() not in ['true', 'false']:
        raise ValueError('Bool erwartet; erhalten %r' % s)
    return {'true': True, 'false': False}[s.lower()]

def add_boolean_argument(parser, name, default=False):                                                                                               
    """Fügt einem ArgumentParser-Objekt ein boolesches Argument hinzu."""
    group = parser.add_mutually_exclusive_group()
    group.add_argument(
        '--' + name, nargs='?', default=default, const=True, type=_str_to_bool)
    group.add_argument('--no' + name, dest=name, action='store_false')

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