Analyse des valeurs booléennes avec argparse
j'aimerais utiliser argparse pour analyser les arguments booléens en ligne de commande écrits comme" --foo True "ou"--foo False". Par exemple:
my_program --my_boolean_flag False
cependant, le code d'essai suivant ne fait pas ce que je voudrais:
import argparse
parser = argparse.ArgumentParser(description="My parser")
parser.add_argument("--my_bool", type=bool)
cmd_line = ["--my_bool", "False"]
parsed_args = parser.parse(cmd_line)
tristement, parsed_args.my_bool
évalue à True
. C'est le cas même lorsque je change cmd_line
pour ["--my_bool", ""]
, ce qui est surprenant, puisque bool("")
est évalué à False
.
Comment obtenir argparse pour analyser "False"
, "F"
, et leurs variantes minuscules pour être False
?
13 réponses
encore une autre solution en utilisant les suggestions précédentes, mais avec l'erreur" correcte " de argparse
:
def str2bool(v):
if v.lower() in ('yes', 'true', 't', 'y', '1'):
return True
elif v.lower() in ('no', 'false', 'f', 'n', '0'):
return False
else:
raise argparse.ArgumentTypeError('Boolean value expected.')
c'est très utile pour faire des commutateurs avec des valeurs par défaut; par exemple
parser.add_argument("--nice", type=str2bool, nargs='?',
const=True, default=NICE,
help="Activate nice mode.")
me permet d'utiliser:
script --nice
script --nice <bool>
et toujours utiliser une valeur par défaut (paramètres de l'utilisateur). L'un des inconvénients (indirectement lié) de cette approche est que le "narguilé" pourrait prendre une position argument -- voir cette question connexe et ce rapport de bogue argparse .
je pense que plus canonique façon de le faire est par le biais de:
command --feature
et
command --no-feature
argparse
supporte cette version bien:
parser.add_argument('--feature', dest='feature', action='store_true')
parser.add_argument('--no-feature', dest='feature', action='store_false')
parser.set_defaults(feature=True)
bien sûr, si vous voulez vraiment la version --arg <True|False>
, vous pouvez passer ast.literal_eval
comme le" type", ou une fonction définie par l'utilisateur ...
def t_or_f(arg):
ua = str(arg).upper()
if 'TRUE'.startswith(ua):
return True
elif 'FALSE'.startswith(ua):
return False
else:
pass #error condition maybe?
je recommande la réponse de mgilson mais avec un groupe mutuellement exclusif
de sorte que vous ne pouvez pas utiliser --feature
et --no-feature
en même temps.
command --feature
et
command --no-feature
mais pas
command --feature --no-feature
Script:
feature_parser = parser.add_mutually_exclusive_group(required=False)
feature_parser.add_argument('--feature', dest='feature', action='store_true')
feature_parser.add_argument('--no-feature', dest='feature', action='store_false')
parser.set_defaults(feature=True)
il semble y avoir une certaine confusion quant à ce que type=bool
et type='bool'
pourrait signifier. Si l'un (ou les deux) signifie 'exécution de la fonction bool()
, ou "retourner un booléen'? En l'état type='bool'
ne signifie rien. add_argument
donne une erreur 'bool' is not callable
, comme si vous aviez utilisé type='foobar'
, ou type='int'
.
mais argparse
a un registre qui vous permet de définir des mots clés comme ceci. Il est principalement utilisé pour action
, par exemple "action= "store_true". Vous pouvez voir les mots clés:
parser._registries
qui affiche un dictionnaire
{'action': {None: argparse._StoreAction,
'append': argparse._AppendAction,
'append_const': argparse._AppendConstAction,
...
'type': {None: <function argparse.identity>}}
il y a beaucoup d'actions définies, mais un seul type, celui par défaut, argparse.identity
.
ce code définit un mot clé "bool":
def str2bool(v):
#susendberg's function
return v.lower() in ("yes", "true", "t", "1")
p = argparse.ArgumentParser()
p.register('type','bool',str2bool) # add type keyword to registries
p.add_argument('-b',type='bool') # do not use 'type=bool'
# p.add_argument('-b',type=str2bool) # works just as well
p.parse_args('-b false'.split())
Namespace(b=False)
parser.register()
n'est pas documentée, mais aussi de ne pas cachés. Pour la plupart, le programmeur n'a pas besoin de le savoir parce que type
et action
prennent des valeurs de fonction et de classe. Il y a beaucoup d'exemples de stackoverflow pour définir des valeurs personnalisées pour les deux.
dans le cas où il n'est pas évident de la discussion précédente, bool()
ne signifie pas 'parse une chaîne de caractères'. De la documentation Python:
bool (x): convertissez une valeur en booléen, en utilisant la procédure standard de test de vérité.
contraste avec
int (x): convertissez un nombre ou une chaîne x en un entier.
je cherchais la même question, et imho la jolie solution est:
def str2bool(v):
return v.lower() in ("yes", "true", "t", "1")
et en utilisant cela pour analyser la chaîne à booléen comme suggéré ci-dessus.
oneliner:
parser.add_argument('--is_debug', default=False, type=lambda x: (str(x).lower() == 'true'))
Voici une autre variation sans ligne / S supplémentaire pour définir les valeurs par défaut. Le bool ont toujours une valeur assignée de sorte qu'il peut être utilisé dans des déclarations logiques sans pré-vérifications.
import argparse
parser = argparse.ArgumentParser(description="Parse bool")
parser.add_argument("--do-something", default=False, action="store_true" , help="Flag to do something")
args = parser.parse_args()
if args.do_something == True:
print("Do something")
else:
print("Don't do something")
print("Check that args.do_something=" + str(args.do_something) + " is always a bool")
en plus de ce que @mgilson a dit, il faut noter qu'il y a aussi une méthode ArgumentParser.add_mutually_exclusive_group(required=False)
qui rendrait futile de faire appliquer que --flag
et --no-flag
ne sont pas utilisés en même temps.
cela fonctionne pour tout ce que j'attends de lui:
add_boolean_argument(parser, 'foo', default=True)
parser.parse_args([]) # Whatever the default was
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']) # Error
le code:
def _str_to_bool(s):
"""Convert string to bool (in argparse context)."""
if s.lower() not in ['true', 'false']:
raise ValueError('Need bool; got %r' % s)
return {'true': True, 'false': False}[s.lower()]
def add_boolean_argument(parser, name, default=False):
"""Add a boolean argument to an ArgumentParser instance."""
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')
Un moyen plus simple serait d'utiliser comme ci-dessous.
parser.add_argument('--feature', type=lambda s: s.lower() in ['true', 't', 'yes', '1'])
class FlagAction(argparse.Action):
# From http://bugs.python.org/issue8538
def __init__(self, option_strings, dest, default=None,
required=False, help=None, metavar=None,
positive_prefixes=['--'], negative_prefixes=['--no-']):
self.positive_strings = set()
self.negative_strings = set()
for string in option_strings:
assert re.match(r'--[A-z]+', string)
suffix = string[2:]
for positive_prefix in positive_prefixes:
self.positive_strings.add(positive_prefix + suffix)
for negative_prefix in negative_prefixes:
self.negative_strings.add(negative_prefix + suffix)
strings = list(self.positive_strings | self.negative_strings)
super(FlagAction, self).__init__(option_strings=strings, dest=dest,
nargs=0, const=None, default=default, type=bool, choices=None,
required=required, help=help, metavar=metavar)
def __call__(self, parser, namespace, values, option_string=None):
if option_string in self.positive_strings:
setattr(namespace, self.dest, True)
else:
setattr(namespace, self.dest, False)
une manière tout à fait similaire est d'utiliser:
feature.add_argument('--feature',action='store_true')
et si vous définissez l'argument -- fonctionnalité dans votre commande
command --feature
l'argument sera True, si vous ne définissez pas type -- feature les arguments par défaut sont toujours False!
je pense que la manière la plus canonique sera:
parser.add_argument('--ensure', nargs='*', default=None)
ENSURE = config.ensure is None