Soyez prudent lorsque vous traitez des valeurs booléennes dans l’argparse de Python.

Affaires

Pour gérer les arguments de la ligne de commande en Python, utilisez les modules argv ou argparse du module sys.

Le module argparse permet une gestion souple des arguments de la ligne de commande, mais il faut faire attention aux valeurs booléennes (true, false).

Les informations suivantes sont fournies ici.

  • argparse pour une définition facile des arguments
  • Spécifier le type de l'argument (type) avec argparse
  • Ne pas spécifier “bool” comme type d'argument de add_argument()
  • Jugement par bool()
  • Utiliser l'action de l'argument au lieu du type d'argument.
  • Utilisation de la fonction strtobool()

argparse pour une définition facile des arguments

Le module argparse permet de définir facilement les arguments de la ligne de commande.

Le module argparse permet de créer facilement des interfaces de ligne de commande conviviales. Vous définissez les arguments dont votre programme a besoin, et argparse se chargera d'analyser ces options à partir de sys.argv. Le module argparse génère automatiquement des messages d'aide et d'utilisation, et génère une erreur si l'utilisateur spécifie des arguments invalides pour le programme.
argparse — Parser for command-line options, arguments and sub-commands — Python 3.10.0 Documentation

Spécifier le type de l'argument (type) avec argparse

Une fonctionnalité utile de argparse est de spécifier le type (type).

Par exemple, si vous spécifiez un type entier (int), il convertira automatiquement l'argument en int et lèvera également une erreur pour les arguments qui ne sont pas int.

Le type est spécifié par le type d'argument de add_argument().

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('arg_int', type=int)

args = parser.parse_args()
print(args.arg_int)
print(type(args.arg_int))

Exécutez ce fichier depuis la ligne de commande.

$ python argparse_type_int.py 100
100
<type 'int'>

L'argument 100 est lu comme int.

Si une valeur non-int est utilisée comme argument, une erreur se produira.

$ python argparse_type_int.py foo
usage: argparse_type_int.py [-h] arg_int
argparse_type_int.py: error: argument arg_int: invalid int value: 'foo'

$ python argparse_type_int.py 1.23
usage: argparse_type_int.py [-h] arg_int
argparse_type_int.py: error: argument arg_int: invalid int value: '1.23'

Très utile pour jouer des arguments inattendus.

Ne pas spécifier “bool” comme type d'argument de add_argument()

Il est important de noter que bool, comme int et float, ne fonctionnera pas comme prévu si vous spécifiez bool comme type d'argument de add_argument().

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('arg_bool', type=bool)

args = parser.parse_args()
print(args.arg_bool)
print(type(args.arg_bool))

Exécutez ce fichier depuis la ligne de commande.

$ python argparse_type_bool.py True
True
<type 'bool'>

Si true est utilisé comme argument, il sera lu comme un bool de type true. C'est le comportement attendu, mais le problème se pose dans le cas suivant.

$ python argparse_type_bool.py False
True
<type 'bool'>

$ python argparse_type_bool.py bar
True
<type 'bool'>

Si vous utilisez false ou toute autre chaîne comme argument, elle sera lue comme true.

La raison pour laquelle cela se produit est que lorsque le type=xxx est spécifié dans add_argument(), l'argument est passé à xxx().

Par exemple, si type=int, l'argument sera transmis à int() ; si type=float, alors float().

Il en va de même pour type=bool, ce qui signifie que l'argument sera transmis à bool().

Jugement par bool()

Ce bool() est délicat.

Les valeurs suivantes sont considérées comme fausses :

  • None
  • false
  • Zéro dans les types numériques. Par exemple, les valeurs suivantes
    • 0
    • 0.0
    • 0j
  • Une séquence vide. Par exemple
    • ''
    • ()
    • []
  • Cartographie vide. Par exemple
    • {}

Toutes les autres valeurs sont supposées être vraies – ainsi, les objets de nombreux types sont toujours vrais. Les opérations et les fonctions intégrées qui renvoient des résultats booléens renvoient toujours 0 ou False comme valeur fausse et 1 ou True comme valeur vraie, sauf indication contraire.

Par conséquent, toutes les chaînes non vides passées à bool(), qu'elles soient 'true' ou 'false', renverront true. Seules les chaînes de caractères vides renverront false.

print(bool('True'))
print(bool('False'))
print(bool('abc'))
# True
# True
# True

print(bool(''))
# False

Lorsque le type=bool est défini dans add_argument(), l'argument est transmis à bool(). Par conséquent, comme le montre l'exemple ci-dessus, si false est utilisé comme argument, il sera converti par bool() en chaîne 'False' et lu comme true.

Utiliser l'action de l'argument au lieu du type d'argument.

Si vous voulez utiliser des valeurs booléennes dans argparse, spécifiez 'store_true' ou 'store_false' pour l'action de l'argument.

  • 'store_true'
  • 'store_false'

Il s'agira de versions spéciales de 'store_const' qui stockeront respectivement True et False. De plus, elles définiront les valeurs par défaut à False et True respectivement, dans cet ordre.
argparse — Parser for command-line options, arguments and sub-commands — Python 3.10.0 Documentation

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--en', action='store_true')

args = parser.parse_args()
print(args.en)
print(type(args.en))

Dans cet exemple, les options suivantes sont données.
--enPar conséquent, si en n'est pas défini comme vrai, il sera chargé comme faux, qui est la valeur par défaut de en.

$ python argparse_option_bool.py --en
True
<type 'bool'>

$ python argparse_option_bool.py
False
<type 'bool'>

Si vous voulez que la valeur par défaut soit true, et false lorsque l'option est ajoutée, il suffit de faire ce qui suit.
action='store_false'

Utilisation de la fonction strtobool()

Si vous souhaitez utiliser des arguments positionnels au lieu d'options, vous pouvez également utiliser la fonction strtobool().

strtobool() est une fonction qui convertit une chaîne de caractères en vrai (1) ou faux (0).

Convertit une chaîne booléenne en vrai (1) ou faux (0).
Les valeurs réelles sont les suivantes

  • y
  • yes
  • true
  • on
  • 1

Les fausses valeurs sont les suivantes.

  • n
  • no
  • f
  • false
  • off
  • 0

Si val n'est pas l'un des éléments ci-dessus, il soulève ValueError.

9. API Reference – strtobool() — Python 3.10.0 Documentation

Il n'est pas sensible à la casse, vous pouvez donc utiliser par exemple la chaîne suivante ; toute autre chaîne entraînera une erreur.

  • 'TRUE'
  • 'True'
  • 'YES'
from distutils.util import strtobool

print(strtobool('true'))
print(strtobool('True'))
print(strtobool('TRUE'))
# 1
# 1
# 1

print(strtobool('t'))
print(strtobool('yes'))
print(strtobool('y'))
print(strtobool('on'))
print(strtobool('1'))
# 1
# 1
# 1
# 1
# 1

print(strtobool('false'))
print(strtobool('False'))
print(strtobool('FALSE'))
# 0
# 0
# 0

print(strtobool('f'))
print(strtobool('no'))
print(strtobool('n'))
print(strtobool('off'))
print(strtobool('0'))
# 0
# 0
# 0
# 0
# 0

# print(strtobool('abc'))
# ValueError: invalid truth value 'abc'

Le nom est strtobool(), mais la valeur de retour n'est pas bool, mais int (1 ou 0).

print(type(strtobool('true')))
# <class 'int'>

Comme écrit précédemment, lorsque le type=xxx est spécifié dans add_argument() de argparse, l'argument sera passé à xxx(). Par conséquent, nous pouvons faire ce qui suit.
type=strtobool

import argparse
from distutils.util import strtobool

parser = argparse.ArgumentParser()
parser.add_argument('arg_bool', type=strtobool)

args = parser.parse_args()
print(args.arg_bool)
print(type(args.arg_bool))

La valeur de retour n'est pas un type bool, mais un type int 1 ou 0, mais elle peut lire des valeurs vraies ou fausses avec true ou false comme arguments.

$ python argparse_type_strtobool.py true
1
<type 'int'>

$ python argparse_type_strtobool.py false
0
<type 'int'>

De même, si l'argument n'est pas attendu, une erreur sera générée correctement.

$ python argparse_type_strtobool.py bar
usage: argparse_type_strtobool.py [-h] arg_bool
argparse_type_strtobool.py: error: argument arg_bool: invalid strtobool value: 'bar'