argumento argparse

Tengo un pequeño problema.

Utilizo argparse para analizar mis argumentos, y está funcionando muy bien.

Para tener los argumentos, yo hago:

 p_args = parser.parse_args(argv) args = dict(p_args._get_kwargs()) 

Pero el problema con p_args es que no sé cómo ordenar estos argumentos por su posición en la línea de comando, porque es un dict.

Entonces, ¿hay alguna posibilidad de tener los argumentos en un tuple / list / orden dict por su orden en la línea de comando?

Para mantener los argumentos ordenados, uso una acción personalizada como esta:

 import argparse class CustomAction(argparse.Action): def __call__(self, parser, namespace, values, option_string=None): if not 'ordered_args' in namespace: setattr(namespace, 'ordered_args', []) previous = namespace.ordered_args previous.append((self.dest, values)) setattr(namespace, 'ordered_args', previous) parser = argparse.ArgumentParser() parser.add_argument('--test1', action=CustomAction) parser.add_argument('--test2', action=CustomAction) 

Para usarlo, por ejemplo:

 >>> parser.parse_args(['--test2', '2', '--test1', '1']) Namespace(ordered_args=[('test2', '2'), ('test1', '1')], test1=None, test2=None) 

Si necesita saber el orden en que aparecen los argumentos en su analizador, puede configurar el analizador de la siguiente manera:

 import argparse parser = argparse.ArgumentParser(description = "A cool application.") parser.add_argument('--optional1') parser.add_argument('positionals', nargs='+') parser.add_argument('--optional2') args = parser.parse_args() print args.positionals 

Aquí hay un ejemplo rápido de ejecutar este código:

 $ python s.py --optional1 X --optional2 Y 1 2 3 4 5 ['1', '2', '3', '4', '5'] 

Tenga en cuenta que args.positionals es una lista con los argumentos posicionales en orden. Consulte la documentación de argparse para más información.

Esto es un poco frágil ya que se basa en la comprensión de los argparse.ArgumentParser internos de argparse.ArgumentParser , pero en lugar de reescribir argparse.ArgumentParser.parse_known_args , esto es lo que uso:

 class OrderedNamespace(argparse.Namespace): def __init__(self, **kwargs): self.__dict__["_arg_order"] = [] self.__dict__["_arg_order_first_time_through"] = True argparse.Namespace.__init__(self, **kwargs) def __setattr__(self, name, value): #print("Setting %s -> %s" % (name, value)) self.__dict__[name] = value if name in self._arg_order and hasattr(self, "_arg_order_first_time_through"): self.__dict__["_arg_order"] = [] delattr(self, "_arg_order_first_time_through") self.__dict__["_arg_order"].append(name) def _finalize(self): if hasattr(self, "_arg_order_first_time_through"): self.__dict__["_arg_order"] = [] delattr(self, "_arg_order_first_time_through") def _latest_of(self, k1, k2): try: print self._arg_order if self._arg_order.index(k1) > self._arg_order.index(k2): return k1 except ValueError: if k1 in self._arg_order: return k1 return k2 

Esto funciona a través del conocimiento de que argparse.ArgumentParser.parse_known_args ejecuta en toda la lista de opciones una vez que establece los valores predeterminados para cada argumento. Lo que significa que los argumentos especificados por el usuario comienzan la primera vez que __setattr__ un argumento que se ha visto antes.

Uso:

 options, extra_args = parser.parse_known_args(sys.argv, namespace=OrderedNamespace()) 

Puede consultar options._arg_order para ver el orden de los argumentos de línea de comandos especificados por el usuario, o usar options._latest_of("arg1", "arg2") para ver cuál de --arg1 o --arg2 se especificó más adelante en la línea de comandos (que , para mis propósitos era lo que necesitaba: ver cuál de las dos opciones sería la más importante.

ACTUALIZACIÓN: tuve que agregar el método _finalize para manejar el caso patológico de sys.argv() no contiene ningún argumento en la lista)

Hay un módulo especialmente hecho para manejar esto:

https://github.com/claylabs/ordered-keyword-args

sin usar el módulo de pedidos de kwargs

 def multiple_kwarguments(first , **lotsofothers): print first for i,other in lotsofothers: print other return True multiple_kwarguments("first", second="second", third="third" ,fourth="fourth" ,fifth="fifth") 

salida:

 first second fifth fourth third 

Sobre el uso del modulo de orden kwargs

 from orderedkwargs import ordered kwargs @orderedkwargs def mutliple_kwarguments(first , *lotsofothers): print first for i, other in lotsofothers: print other return True mutliple_kwarguments("first", second="second", third="third" ,fourth="fourth" ,fifth="fifth") 

Salida:

 first second third fourth fifth 

Nota: Se requiere un solo asterisco al usar este módulo con el decorador sobre la función.

Necesitaba esto porque, para fines de registro, me gustaba imprimir los argumentos después de que se analizaran. El problema fue que los argumentos no se imprimen en orden, lo que fue realmente molesto.

La clase de acción personalizada simplemente no funcionó para mí. Tuve otros argumentos que utilizaron una acción diferente, como 'store_true' y default argumentos default tampoco funcionan, ya que la clase de acción personalizada no se llama si el argumento no se da en la línea de comandos. Lo que funcionó para mí fue crear una clase de envoltura como esta:

 import collections from argparse import ArgumentParser class SortedArgumentParser(): def __init__(self, *args, **kwargs): self.ap = ArgumentParser(*args, **kwargs) self.args_dict = collections.OrderedDict() def add_argument(self, *args, **kwargs): self.ap.add_argument(*args, **kwargs) # Also store dest kwarg self.args_dict[kwargs['dest']] = None def parse_args(self): # Returns a sorted dictionary unsorted_dict = self.ap.parse_args().__dict__ for unsorted_entry in unsorted_dict: self.args_dict[unsorted_entry] = unsorted_dict[unsorted_entry] return self.args_dict 

Las ventajas son que el método add_argument debe tener exactamente la misma funcionalidad que el ArgumentParser original. Los contras son que si quieres otros métodos tendrás que escribir envuelto para todos ellos. Por suerte para mí, todo lo que usé fue add_argument y parse_args , así que esto me sirvió bastante bien. También necesitarías hacer más trabajo si quisieras usar ArgumentParser padres.