parser - python argparse optional
Python Argparse: Problema con argumentos opcionales que son nĂºmeros negativos (7)
Estoy teniendo un pequeño problema con argparse
. Tengo una opción xlim
que es el xrange
de una parcela. Quiero poder pasar números como -2e-5
. Sin embargo, esto no funciona; argparse
interpreta que este es un argumento posicional. Si hago -0.00002
funciona: argparse
lee como un número negativo. ¿Es posible tener lectura en -2e-3
?
El código está abajo, y un ejemplo de cómo lo ejecutaría es:
./blaa.py --xlim -2.e-3 1e4
Si hago lo siguiente funciona:
./blaa.py --xlim -0.002 1e4
El código:
parser.add_argument(''--xlim'', nargs = 2,
help = ''X axis limits'',
action = ''store'', type = float,
default = [-1.e-3, 1.e-3])
Si bien puedo hacerlo funcionar de esta manera, realmente preferiría poder usar la notación científica. ¿Alguien tiene alguna idea?
Aclamaciones
Aquí está el código que utilizo. (Es similar a la de jeremiahbuddha, pero responde a la pregunta más directamente ya que trata con números negativos).
Coloca esto antes de llamar a argparse.ArgumentParser()
for i, arg in enumerate(sys.argv):
if (arg[0] == ''-'') and arg[1].isdigit(): sys.argv[i] = '' '' + arg
Como ya se señaló en los comentarios, el problema es que un prefijo se analiza como una opción en lugar de como un argumento. Una forma de solucionar esto es cambiar el prefijo utilizado para las opciones con el argumento prefix_chars
:
#!/usr/bin/python
import argparse
parser = argparse.ArgumentParser(prefix_chars=''@'')
parser.add_argument(''@@xlim'', nargs = 2,
help = ''X axis limits'',
action = ''store'', type = float,
default = [-1.e-3, 1.e-3])
print parser.parse_args()
Ejemplo de salida:
$ ./blaa.py @@xlim -2.e-3 1e4
Namespace(xlim=[-0.002, 10000.0])
Edición: Alternativamente, puede seguir usando -
como separador, pasar xlim
como un solo valor y usar una función de type
para implementar su propio análisis:
#!/usr/bin/python
import argparse
def two_floats(value):
values = value.split()
if len(values) != 2:
raise argparse.ArgumentError
values = map(float, values)
return values
parser = argparse.ArgumentParser()
parser.add_argument(''--xlim'',
help = ''X axis limits'',
action = ''store'', type=two_floats,
default = [-1.e-3, 1.e-3])
print parser.parse_args()
Ejemplo de salida:
$ ./blaa.py --xlim "-2e-3 1e4"
Namespace(xlim=[-0.002, 10000.0])
Inspirado por el enfoque de andrewfn, creé una función de ayuda separada para hacer el violín de sys.argv
:
def _tweak_neg_scinot():
import re
import sys
p = re.compile(''-//d*//.?//d*e'', re.I)
sys.argv = ['' '' + a if p.match(a) else a for a in sys.argv]
El regex busca:
-
-
: un signo negativo -
//d*
: cero o más dígitos (para valores con formato extraño como-.5e-2
o-4354.5e-6
) -
//.?
: un período opcional (por ejemplo,-2e-5
es razonable) -
//d*
: otro conjunto de cero o más dígitos (para cosas como-2e-5
y-7.e-3
) -
e
: para hacer coincidir el marcador de exponente
re.I
hace que coincida con -2e-5
y -2E-5
. Usar p.match
significa que solo busca desde el inicio de cada cadena.
Otra solución es pasar el argumento usando el símbolo '' =
'' además de citar el argumento, es decir, --xlim="-2.3e14"
Si especifica el valor de su opción con un signo igual, argparse
no lo tratará como una opción separada, incluso si comienza con -
:
./blaa.py --xlim=''-0.002 1e4''
# As opposed to --xlim ''-0.002 1e4''
Y si el valor no tiene espacios, puede eliminar las comillas:
./blaa.py --xlim=-0.002
Consulte: https://www.gnu.org/software/guile/manual/html_node/Command-Line-Format.html
Con esto, no es necesario escribir su propio type=
analizador o redefinir el carácter de prefijo de -
a @
como sugiere la respuesta aceptada.
Si está modificando el propio argparse.py
, podría cambiar el emparejador de números negativos para manejar la notación científica:
En la class _ActionsContainer.__init__()
self._negative_number_matcher = _re.compile(r''^-(/d+/.?|/d*/./d+)([eE][+/-]?/d+)?$'')
O después de crear el analizador, puede establecer parser._negative_number_matcher
en este valor. Este enfoque podría tener problemas si está creando grupos o subparsers, pero debería funcionar con un analizador simple.
Una solución que he encontrado es citar el valor, pero agregar un espacio. Es decir,
./blaa.py --xlim " -2.e-3" 1e4
De esta manera, argparse no pensará que -2.e-3 es un nombre de opción porque el primer carácter no es un guión con guión, pero aún se convertirá correctamente en un flotador porque flotante (cadena) ignora los espacios de la izquierda.