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 -ibandera 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 argumentcaso (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=3ymetavar=('url','name','other')?La tupla
metavartambié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
-idebe configurarse para aceptar 3 argumentos y utilizar laappendacció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
-ies 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_vares opcional.