J'essaie d'obtenir le comportement suivant:
Ça marche quand j'utilise
parser.add_argument('--foo',nargs='?', default=False, const=True)
Cependant ça casse si j'ajoute type=bool
, en essayant d'imposer le casting à booléen. Dans ce cas
python test.py --foo False
En fait, finit par stocker foo=True
. Que se passe-t-il??
Êtes-vous sûr que vous avez besoin de ce modèle? --foo
Et --foo <value>
, Ensemble, pour un commutateur booléen, n'est pas un modèle courant à utiliser.
Quant à votre problème, rappelez-vous que la valeur de la ligne de commande est une chaîne et que type=bool
Signifie que vous voulez bool(entered-string-value)
à appliquer. Pour --foo False
, Cela signifie bool("False")
, produisant True
; toutes les chaînes non vides sont vraies! Voir Pourquoi argparse n'analyse-t-il pas correctement mon drapeau booléen? également.
Au lieu de prendre en charge --foo
/--foo <string value>
, Je fortement vous recommande d'utiliser --foo
Pour signifier True
, supprimez la valeur de l'argument et ajoutez à la place une option --no-foo
pour définir explicitement False
:
parser.add_argument('--foo', default=False, action='store_true')
parser.add_argument('--no-foo', dest='foo', action='store_false')
L'ajout de dest='foo'
Sur le commutateur --no-foo
Garantit que la valeur False
qu'il stocke (via store_false
) Se retrouve sur le même attribut args.foo
.
Vous n'auriez besoin d'une combinaison --foo / --no-foo
Que si vous avez un autre mécanisme de configuration qui définirait foo
sur True
et que vous deviez le remplacer à nouveau avec un commutateur de ligne de commande. --no-<option>
Est une norme largement adoptée pour inverser un commutateur de ligne de commande booléen.
Si vous n'avez pas un besoin spécifique pour un interrupteur inversé --no-foo
(Car juste en omettant --foo
Signifierait déjà 'faux'), alors restez avec l'option action='store_true'
. Cela rend votre ligne de commande simple et claire!
Cependant, si votre cas d'utilisation ou d'autres contraintes nécessitent spécifiquement que votre ligne de commande doive avoir un certain support de --foo (true|false|0|1)
, alors ajoutez votre propre convertisseur:
def str_to_bool(value):
if isinstance(value, bool):
return value
if value.lower() in {'false', 'f', '0', 'no', 'n'}:
return False
Elif value.lower() in {'true', 't', '1', 'yes', 'y'}:
return True
raise ValueError(f'{value} is not a valid boolean value')
parser.add_argument('--foo', type=str_to_bool, nargs='?', const=True, default=False)
const
est utilisée pour les arguments nargs='?'
où la valeur d'argument est omise. Ici, cela définit foo=True
Lorsque --foo
Est utilisé.default=False
Est utilisé lorsque le commutateur n'est pas utilisé du tout.type=str_to_bool
Est utilisé pour gérer le cas --foo <value>
.Démo:
$ cat so52403065.py
from argparse import ArgumentParser
parser = ArgumentParser()
def str_to_bool(value):
if value.lower() in {'false', 'f', '0', 'no', 'n'}:
return False
Elif value.lower() in {'true', 't', '1', 'yes', 'y'}:
return True
raise ValueError(f'{value} is not a valid boolean value')
parser.add_argument('--foo', type=str_to_bool, nargs='?', const=True, default=False)
print(parser.parse_args())
$ python so52403065.py
Namespace(foo=False)
$ python so52403065.py --foo
Namespace(foo=True)
$ python so52403065.py --foo True
Namespace(foo=True)
$ python so52403065.py --foo no
Namespace(foo=False)
$ python so52403065.py --foo arrbuggrhellno
usage: so52403065.py [-h] [--foo [FOO]]
so52403065.py: error: argument --foo: invalid str_to_bool value: 'arrbuggrhellno'
Vous devez utiliser le action='store_true'
paramètre à la place pour les arguments booléens:
parser.add_argument('--foo', action='store_true')
Pour que l'absence de --foo
option:
python test.py
entraînerait une valeur False
pour l'argument foo
et la présence de --foo
option:
python test.py --foo
entraînerait une valeur True
pour l'argument foo
.