Python argparse store --foo = bar como args.key = 'foo', args.value = 'bar'

Me gustaría analizar una línea de comando que tiene un grupo de opciones mutuamente excluyentes. Normalmente, solo usaría--foo bar que produciría, en el espacio de nombres,args.foo = 'bar'

Sin embargo, dado que todas estas opciones son mutuamente excluyentes, y estoy interesado tanto en el nombre de la opción como en el argumento pasado a la opción, y tengo varias de estas opciones que deben alimentarse en sentido descendente, lo que realmente me gustaría es volverargs.option_name = 'foo', args.option_value = 'bar' en mi espacio de nombres en lugar deargs.foo='bar'.

Lo que he hecho es:

class KeyAction(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        setattr(namespace, self.dest, values) 
        setattr(namespace, self.dest+'_key', option_string)

frob = parser.add_mutually_exclusive_group()
frob.add_argument('--foo', dest='thing', nargs='?', action=KeyAction)
frob.add_argument('--nar', dest='thing', nargs='?', action=KeyAction)

cuando se ejecute, mi espacio de nombres se verá así:

Namespace(thing_key='--foo', thing='bar')

cuando--foo=bar es analizado Por supuesto, lamentablemente, si --foo o --nar nunca se pasa,namespace.thing_key no se define, así que tengo que usar ungetattr().

La anulación de la acción, aunque funcional, no parece realmente correcta.

Sospecho que las mentes brillantes detrás de argparse ya lo entendieron de alguna manera, y solo me falta en la documentación y en mi lectura de argparse.py.

¿Cuál es la mejor manera, correcta, pitónica, de hacer esto? Subparsers? Estoy usando python 3.5.

Así que terminé usando datos de sus dos respuestas para construir esto, que maneja la opción, su argumento y establece todo sensiblemente en el momento de la inicialización.

Muchas gracias por las sugerencias, pistas y validación. Me sorprende que esto no haya aparecido antes en argparse y se haya convertido en algo estandarizado. Esoes un caso de esquina, pero no es tanto un caso de esquinacuando se usan opciones mutuamente excluyentes.

    class ValueAction(argparse.Action):
        """Override to store both the format type as well as the argument"""
        # pylint: disable=too-few-public-methods
        def __init__(self, option_strings, dest, **kwargs):
            self._dest = dest
            dest = dest + '_arguments'
            container = kwargs.pop('container')
            kwargs['action'] = kwargs.pop('subaction')
            action_class = container._pop_action_class(kwargs)
            if not callable(action_class):
                raise ValueError('unknown action "%s"' % (action_class,))
            self._action = action_class(option_strings, dest, **kwargs)
            super().__init__(option_strings, dest, **kwargs)

        def __call__(self, parser, namespace, values, option_string=None):
            self._action(parser, namespace, values, option_string)
            if isinstance(option_string, str):
                while option_string[0] in parser.prefix_chars:
                    option_string = option_string[1:]
            setattr(namespace, self._dest, option_string)

Respuestas a la pregunta(2)

Su respuesta a la pregunta