Luego de investigar con expertos en la materia, programadores de diversas ramas y maestros dimos con la respuesta al problema y la compartimos en esta publicación.
Solución:
TL;RD
Utilizar el nargs
opción o la 'append'
ajuste de la action
opción (dependiendo de cómo desee que se comporte la interfaz de usuario).
Nargs
parser.add_argument('-l','--list', nargs='+', help=' Set flag', required=True)
# Use like:
# python arg.py -l 1234 2345 3456 4567
nargs='+'
toma 1 o más argumentos, nargs='*'
toma cero o más.
adjuntar
parser.add_argument('-l','--list', action='append', help=' Set flag', required=True)
# Use like:
# python arg.py -l 1234 -l 2345 -l 3456 -l 4567
Con append
proporciona la opción varias veces para crear la lista.
no usar type=list
!!! – Probablemente no haya ninguna situación en la que desee utilizar type=list
con argparse
. Siempre.
Echemos un vistazo con más detalle a algunas de las diferentes formas en que uno podría intentar hacer esto y el resultado final.
import argparse
parser = argparse.ArgumentParser()
# By default it will fail with multiple arguments.
parser.add_argument('--default')
# Telling the type to be a list will also fail for multiple arguments,
# but give incorrect results for a single argument.
parser.add_argument('--list-type', type=list)
# This will allow you to provide multiple arguments, but you will get
# a list of lists which is not desired.
parser.add_argument('--list-type-nargs', type=list, nargs='+')
# This is the correct way to handle accepting multiple arguments.
# '+' == 1 or more.
# '*' == 0 or more.
# '?' == 0 or 1.
# An int is an explicit number of arguments to accept.
parser.add_argument('--nargs', nargs='+')
# To make the input integers
parser.add_argument('--nargs-int-type', nargs='+', type=int)
# An alternate way to accept multiple inputs, but you must
# provide the flag once per input. Of course, you can use
# type=int here if you want.
parser.add_argument('--append-action', action='append')
# To show the results of the given option to screen.
for _, value in parser.parse_args()._get_kwargs():
if value is not None:
print(value)
Aquí está el resultado que puede esperar:
$ python arg.py --default 1234 2345 3456 4567
...
arg.py: error: unrecognized arguments: 2345 3456 4567
$ python arg.py --list-type 1234 2345 3456 4567
...
arg.py: error: unrecognized arguments: 2345 3456 4567
$ # Quotes won't help here...
$ python arg.py --list-type "1234 2345 3456 4567"
['1', '2', '3', '4', ' ', '2', '3', '4', '5', ' ', '3', '4', '5', '6', ' ', '4', '5', '6', '7']
$ python arg.py --list-type-nargs 1234 2345 3456 4567
[['1', '2', '3', '4'], ['2', '3', '4', '5'], ['3', '4', '5', '6'], ['4', '5', '6', '7']]
$ python arg.py --nargs 1234 2345 3456 4567
['1234', '2345', '3456', '4567']
$ python arg.py --nargs-int-type 1234 2345 3456 4567
[1234, 2345, 3456, 4567]
$ # Negative numbers are handled perfectly fine out of the box.
$ python arg.py --nargs-int-type -1234 2345 -3456 4567
[-1234, 2345, -3456, 4567]
$ python arg.py --append-action 1234 --append-action 2345 --append-action 3456 --append-action 4567
['1234', '2345', '3456', '4567']
comida para llevar:
- Utilizar
nargs
oaction='append'
nargs
puede ser más sencillo desde la perspectiva del usuario, pero puede ser poco intuitivo si hay argumentos posicionales porqueargparse
no puedo decir lo que debería ser un argumento posicional y lo que pertenece a lanargs
; si tienes argumentos posicionales entoncesaction='append'
puede terminar siendo una mejor opción.- Lo anterior es solo true si
nargs
es dado'*'
,'+'
o'?'
. Si proporciona un número entero (como4
) entonces no habrá problemas para mezclar opciones connargs
y argumentos posicionales porqueargparse
sabrá exactamente cuántos valores esperar para la opción.
- No use comillas en la línea de comando1
- no usar
type=list
ya que devolverá una lista de listas- Esto sucede porque debajo del capó
argparse
utiliza el valor detype
coaccionar cada argumento individual dado eres tu elegidotype
no el agregado de todos los argumentos. - Puedes usar
type=int
(o lo que sea) para obtener una lista de enteros (o lo que sea)
- Esto sucede porque debajo del capó
1: No me refiero en general… Me refiero a usar comillas para pasar una lista a argparse
no es lo que quieres.
Prefiero pasar un delimitado string que analizo más adelante en el script. Las razones de esto son; la lista puede ser de cualquier tipo int
o str
y a veces usando nargs
Me encuentro con problemas si hay múltiples argumentos opcionales y argumentos posicionales.
parser = ArgumentParser()
parser.add_argument('-l', '--list', help='delimited list input', type=str)
args = parser.parse_args()
my_list = [int(item) for item in args.list.split(',')]
Luego,
python test.py -l "265340,268738,270774,270817" [other arguments]
o,
python test.py -l 265340,268738,270774,270817 [other arguments]
funcionará bien. El delimitador también puede ser un espacio, lo que impondría comillas alrededor del valor del argumento, como en el ejemplo de la pregunta.
O puede usar un tipo lambda como se sugiere en los comentarios de Chepner:
parser.add_argument('-l', '--list', help='delimited list input',
type=lambda s: [int(item) for item in s.split(',')])
Además de nargs
es posible que desee utilizar choices
si conoces la lista de antemano:
>>> parser = argparse.ArgumentParser(prog='game.py')
>>> parser.add_argument('move', choices=['rock', 'paper', 'scissors'])
>>> parser.parse_args(['rock'])
Namespace(move='rock')
>>> parser.parse_args(['fire'])
usage: game.py [-h] rock,paper,scissors
game.py: error: argument move: invalid choice: 'fire' (choose from 'rock',
'paper', 'scissors')
Si te ha sido provechoso este post, sería de mucha ayuda si lo compartieras con más desarrolladores y nos ayudes a difundir nuestra información.