Pregunta

Si tengo los argumentos '-a', '-b', '-c', '-d', con el add_mutually_exclusive_group() Función Mi programa tendrá que usar solo uno de ellos. ¿Hay alguna forma de combinar eso, para que el programa solo acepte '-a 999 -b 999' o '-c 999 -d 999'?

Editar: Agregar un programa simple para obtener más claridad:

>>> parser = argparse.ArgumentParser()
>>> group = parser.add_mutually_exclusive_group()
>>> group.add_argument('-a')
>>> group.add_argument('-b')
>>> group.add_argument('-c')
>>> group.add_argument('-d')

Entonces solo ./app.py -a | ./app.py -b | ./app.py -c | ./app.py -d puede ser llamado. ¿Es posible tener a Argparse Group los grupos de exclusión, de modo que solo ./app.py -a .. -b .. | ./app.py -c .. -d .. ¿ser llamado?

¿Fue útil?

Solución

EDITAR: No importa. Porque argparse Hace la horrible elección de tener que crear una opción al invocar group.add_argument. Esa no sería mi elección de diseño. Si estás desesperado por esta función, puedes intentar hacerlo con ConflictSoptionParser:

# exclusivegroups.py
import conflictsparse

parser = conflictsparse.ConflictsOptionParser()
a_opt = parser.add_option('-a')
b_opt = parser.add_option('-b')
c_opt = parser.add_option('-c')
d_opt = parser.add_option('-d')

import itertools
compatible_opts1 = (a_opt, b_opt)
compatible_opts2 = (c_opt, d_opt)
exclusives = itertools.product(compatible_opts1, compatible_opts2)
for exclusive_grp in exclusives:
    parser.register_conflict(exclusive_grp)


opts, args = parser.parse_args()
print "opts: ", opts
print "args: ", args

Por lo tanto, cuando lo invocamos, podemos ver que obtenemos el efecto deseado.

$ python exclusivegroups.py -a 1 -b 2
opts:  {'a': '1', 'c': None, 'b': '2', 'd': None}
args:  []
$ python exclusivegroups.py -c 3 -d 2
opts:  {'a': None, 'c': '3', 'b': None, 'd': '2'}
args:  []
$ python exclusivegroups.py -a 1 -b 2 -c 3
Usage: exclusivegroups.py [options]

exclusivegroups.py: error: -b, -c are incompatible options.

El mensaje de advertencia no le informa que ambos '-a' y '-b' son incompatibles con '-c', sin embargo, se podría elaborar un mensaje de error más apropiado. Anterior, respuesta incorrecta a continuación.

Edición anterior: Esta edición está mal, aunque ¿no sería solo un mundo perfecto si argparse funcionó de esta manera? Mi respuesta anterior en realidad fue incorrecta, deberías poder hacer esto con argparse especificando un grupo por opciones mutuamente excluyentes. Incluso podemos usar itertools Para generalizar el proceso. Y hazlo para que no tengamos que escribir todas las combinaciones explícitamente:

import itertools
compatible_opts1 = ('-a', '-b')
compatible_opts2 = ('-c', '-d')
exclusives = itertools.product(compatible_opts1, compatible_opts2)
for exclusive_grp in exclusives:
    group = parser.add_mutually_exclusive_group()
    group.add_argument(exclusive_grp[0])
    group.add_argument(exclusive_grp[1])

Otros consejos

Me tropecé con este problema yo mismo. Desde mi lectura de los documentos de Argparse, no parece haber una forma simple de lograrlo dentro de Argparse. Pensé en usar parse_ conocido_args, pero eso pronto equivale a escribir una versión de uso especial de Argparse ;-)

Quizás un informe de error está en orden. Mientras tanto, si está dispuesto a hacer que su usuario haga un poco de escritura adicional, puede fingirlo con subgrupos (como cómo funcionan los argumentos de GIT y SVN), por ejemplo,

    subparsers = parser.add_subparsers()
    p_ab = subparsers.add_parser('ab')
    p_ab.add_argument(...)

    p_cd = subparsers.add_parser('cd')
    p_cd.add_argument(...)

No es ideal, pero al menos te da lo bueno de Argparse sin demasiada hackería fea. Terminé eliminando los interruptores y solo usando las operaciones de subparrador con subargumentos requeridos.

¿Subparsers?

Similar a unhammerRespuesta, pero con más control de usuario. Nota: En realidad no he probado este método, pero debería funcionar en teoría y con las capacidades de Python.

Puede crear dos analizadores, uno para cada uno de los dos grupos, y usar condicionales para hacer la parte mutuamente excluyente. Esencialmente, usando Argparse solo para una parte del análisis de argumentos. Usando este método, puede ir más allá de las limitaciones de unhammerLa respuesta también.

# Python 3
import argparse

try:
    parser = argparse.ArgumentParser()
    parser.add_argument('-a')
    parser.add_argument('-b')
    args = parser.parse_args
except argparse.ArgumentError:
    parser = argparse.ArgumentParser()
    parser.add_argument('-c')
    parser.add_argument('-d')
    args = parser.parse_args
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top