Saltar al contenido

¿Cómo puedo pasar una lista como argumento de línea de comandos con argparse?

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 o action='append'
    • nargs puede ser más sencillo desde la perspectiva del usuario, pero puede ser poco intuitivo si hay argumentos posicionales porque argparse no puedo decir lo que debería ser un argumento posicional y lo que pertenece a la nargs; si tienes argumentos posicionales entonces action='append' puede terminar siendo una mejor opción.
    • Lo anterior es solo true si nargs es dado '*', '+'o '?'. Si proporciona un número entero (como 4) entonces no habrá problemas para mezclar opciones con nargs y argumentos posicionales porque argparse sabrá exactamente cuántos valores esperar para la opción.
  • No use comillas en la línea de comando1
  • no usar type=listya que devolverá una lista de listas
    • Esto sucede porque debajo del capó argparse utiliza el valor de type coaccionar cada argumento individual dado eres tu elegido typeno el agregado de todos los argumentos.
    • Puedes usar type=int (o lo que sea) para obtener una lista de enteros (o lo que sea)

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 stry 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 nargses 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.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *