Fate attenzione quando trattate con valori booleani nell’argparse di Python

Attività commerciale

Per gestire gli argomenti della riga di comando in Python, usate i moduli argv o argparse del modulo sys.

Il modulo argparse permette una gestione flessibile degli argomenti della riga di comando, ma bisogna fare attenzione quando si tratta di valori booleani (vero, falso).

Le seguenti informazioni sono fornite qui.

  • argparse per una facile definizione degli argomenti
  • Specificare il tipo di argomento (type) con argparse
  • Non specificare “bool” come tipo di argomento di add_argument()
  • Sentenza di bool()
  • Usa l'azione dell'argomento invece del tipo di argomento.
  • Usando la funzione strtobool()

argparse per una facile definizione degli argomenti

Il modulo argparse rende facile definire gli argomenti della linea di comando.

Il modulo argparse rende facile la creazione di interfacce a riga di comando user-friendly. Voi definite di quali argomenti ha bisogno il vostro programma, e argparse capirà come analizzare queste opzioni da sys.argv. Il modulo argparse genera automaticamente messaggi di aiuto e di utilizzo, e solleva un errore se l'utente specifica argomenti non validi al programma. error when the user specifies invalid arguments to the program.
argparse — Parser for command-line options, arguments and sub-commands — Python 3.10.0 Documentation

Specificare il tipo di argomento (type) con argparse

Una caratteristica utile di argparse è quella di specificare il tipo (type).

Per esempio, se specificate un tipo intero (int), convertirà automaticamente l'argomento in int e solleverà anche un errore per gli argomenti che non sono int.

Il tipo è specificato dal tipo di argomento di 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))

Eseguite questo file dalla linea di comando.

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

L'argomento 100 viene letto come int.

Se viene usato un valore non-int come argomento, si verificherà un errore.

$ 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'

Molto utile per riprodurre argomenti inaspettati.

Non specificare “bool” come tipo di argomento di add_argument()

È importante notare che bool, come int e float, non funziona come previsto se si specifica bool come tipo di argomento di 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))

Eseguite questo file dalla linea di comando.

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

Se true è usato come argomento, sarà letto come un bool di tipo true. Questo è il comportamento atteso, ma il problema è il seguente caso.

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

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

Se usate false o qualsiasi altra stringa come argomento, sarà letta come true.

La ragione per cui questo accade è che quando type=xxx è specificato in add_argument(), l'argomento viene passato a xxx().

Per esempio, se tipo=int, l'argomento sarà passato a int(); se tipo=float, allora float().

Lo stesso vale per type=bool, che significa che l'argomento sarà passato a bool().

Sentenza di bool()

Questo bool() è complicato.

I seguenti valori sono considerati falsi:

  • None
  • false
  • Zero nei tipi numerici. Per esempio, i seguenti valori
    • 0
    • 0.0
    • 0j
  • Una sequenza vuota. Per esempio
    • ''
    • ()
    • []
  • Mappatura vuota. Per esempio
    • {}

Tutti gli altri valori sono assunti come veri – così gli oggetti di molti tipi sono sempre veri. Le operazioni e le funzioni integrate che restituiscono risultati booleani restituiscono sempre 0 o False come valore falso e 1 o True come valore vero, a meno che non sia indicato diversamente.

Pertanto, tutte le stringhe non vuote passate a bool(), sia 'true' che 'false', restituiranno true. Solo le stringhe vuote saranno false.

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

print(bool(''))
# False

Quando type=bool è impostato in add_argument(), l'argomento viene passato a bool(). Pertanto, come mostrato nell'esempio precedente, se viene usato false come argomento, sarà convertito da bool() come la stringa 'False' e letto come true.

Usa l'azione dell'argomento invece del tipo di argomento.

Se volete usare valori booleani in argparse, specificate 'store_true' o 'store_false' per l'azione argomento.

  • 'store_true'
  • 'store_false'

Queste saranno versioni speciali di 'store_const' che memorizzeranno rispettivamente True e False. Inoltre, imposteranno i valori di default rispettivamente a False e True, in questo ordine.
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))

In questo esempio, vengono date le seguenti opzioni.
--enPertanto, se en non è impostato come true, sarà caricato come false, che è il valore predefinito di en.

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

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

Se volete impostare il default a true, e false quando l'opzione viene aggiunta, fate semplicemente come segue.
action='store_false'

Usando la funzione strtobool()

Se volete usare argomenti posizionali invece di opzioni, potete anche usare la funzione strtobool().

strtobool() è una funzione che converte una stringa in vero (1) o falso (0).

Converte una stringa booleana in vero (1) o falso (0).
I valori veri sono i seguenti

  • y
  • yes
  • true
  • on
  • 1

I valori falsi sono i seguenti.

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

Se val non è uno dei precedenti, solleva ValueError.

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

Non è sensibile alle maiuscole e alle minuscole, quindi, per esempio, potete usare il seguente; qualsiasi altra stringa risulterà in un errore.

  • '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'

Il nome è strtobool(), ma il valore di ritorno non è bool, ma int (1 o 0).

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

Come scritto in precedenza, quando type=xxx è specificato in add_argument() di argparse, l'argomento sarà passato a xxx(). Pertanto, possiamo fare quanto segue.
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))

Il valore di ritorno non è un tipo bool, ma un int di tipo 1 o 0, ma può leggere valori veri o falsi con true o false come argomenti.

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

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

Inoltre, se l'argomento non è previsto, verrà generato correttamente un errore.

$ 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'