Estoy tratando de escribir un script que acepte múltiples fuentes de entrada y haga algo con cada una. Algo como esto
./my_script.py \
-i input1_url input1_name input1_other_var \
-i input2_url input2_name input2_other_var \
-i input3_url input3_name
# notice inputX_other_var is optional
Pero no puedo entender cómo hacer esto usando argparse
. Parece que está configurado para que cada indicador de opción solo se pueda usar una vez. Sé cómo asociar varios argumentos con una sola opción ( nargs='*'
o nargs='+'
), pero eso aún no me permite usar la -i
bandera varias veces. ¿Cómo hago para lograr esto?
Para que quede claro, lo que me gustaría al final es una lista de listas de cadenas. Entonces
[["input1_url", "input1_name", "input1_other"],
["input2_url", "input2_name", "input2_other"],
["input3_url", "input3_name"]]
python
argparse
multiple-arguments
John Allard
fuente
fuente
Respuestas:
Aquí hay un analizador que maneja un argumento 2 repetido opcional, con nombres definidos en
metavar
:parser=argparse.ArgumentParser() parser.add_argument('-i','--input',action='append',nargs=2, metavar=('url','name'),help='help:') In [295]: parser.print_help() usage: ipython2.7 [-h] [-i url name] optional arguments: -h, --help show this help message and exit -i url name, --input url name help: In [296]: parser.parse_args('-i one two -i three four'.split()) Out[296]: Namespace(input=[['one', 'two'], ['three', 'four']])
Esto no maneja el
2 or 3 argument
caso (aunque escribí un parche hace algún tiempo para un error / problema de Python que manejaría tal rango).¿Qué tal una definición de argumento separada con
nargs=3
ymetavar=('url','name','other')
?La tupla
metavar
también se puede utilizar connargs='+'
ynargs='*'
; las 2 cadenas se utilizan como[-u A [B ...]]
o[-u [A [B ...]]]
.fuente
Esto es simple; simplemente agregue ambos
action='append'
ynargs='*'
(o'+'
).import argparse parser = argparse.ArgumentParser() parser.add_argument('-i', action='append', nargs='+') args = parser.parse_args()
Luego, cuando lo ejecutas, obtienes
In [32]: run test.py -i input1_url input1_name input1_other_var -i input2_url i ...: nput2_name input2_other_var -i input3_url input3_name In [33]: args.i Out[33]: [['input1_url', 'input1_name', 'input1_other_var'], ['input2_url', 'input2_name', 'input2_other_var'], ['input3_url', 'input3_name']]
fuente
-i
debe configurarse para aceptar 3 argumentos y utilizar laappend
acción.>>> p = argparse.ArgumentParser() >>> p.add_argument("-i", nargs=3, action='append') _AppendAction(...) >>> p.parse_args("-i a b c -i d e f -i g h i".split()) Namespace(i=[['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']])
Para manejar un valor opcional, puede intentar usar un tipo personalizado simple. En este caso, el argumento de
-i
es una única cadena delimitada por comas, con el número de divisiones limitado a 2. Debería procesar posteriormente los valores para asegurarse de que haya al menos dos valores especificados.>>> p.add_argument("-i", type=lambda x: x.split(",", 2), action='append') >>> print p.parse_args("-i a,b,c -i d,e -i g,h,i,j".split()) Namespace(i=[['a', 'b', 'c'], ['d', 'e'], ['g', 'h', 'i,j']])
Para mayor control, defina una acción personalizada. Este extiende el incorporado
_AppendAction
(usado poraction='append'
), pero solo hace una verificación de rango en el número de argumentos dados-i
.class TwoOrThree(argparse._AppendAction): def __call__(self, parser, namespace, values, option_string=None): if not (2 <= len(values) <= 3): raise argparse.ArgumentError(self, "%s takes 2 or 3 values, %d given" % (option_string, len(values))) super(TwoOrThree, self).__call__(parser, namespace, values, option_string) p.add_argument("-i", nargs='+', action=TwoOrThree)
fuente
inputX_other_var
es opcional.