Python Argparse: Problema con argumentos opcionales que son números negativos
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 lo hago -0.00002
funciona: argparse
lo lee como un número negativo. ¿Es posible tener capaz de leer en -2e-3
?
El código está a continuación, y un ejemplo de cómo lo ejecutaría es:
./blaa.py --xlim -2.e-3 1e4
Si hago lo siguiente funciona: {[12]]}
./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 hacer que funcione de esta manera, realmente preferiría poder usar la notación científica. Alguien tiene alguna idea?
Salud
7 answers
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 prefix_chars
argumento:
#!/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])
Editar: Alternativamente, puede seguir usando -
como separador, pasar xlim
como un solo valor y usar una función en 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])
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-27 12:07:32
Una solución que he encontrado es citar el valor, pero añadiendo un espacio. Es decir,
./blaa.py --xlim " -2.e-3" 1e4
De esta manera argparse no pensará -2.e-3 es un nombre de opción porque el primer carácter no es un guion, pero aún así se convertirá correctamente a un flotador porque float(cadena) ignora los espacios de la izquierda.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-21 13:13:45
Si está dispuesto a modificar argparse.py
en sí, podría cambiar el matcher de números negativos para manejar la notación científica:
self._negative_number_matcher = _re.compile(r'^-(\d+\.?|\d*\.\d+)([eE][+\-]?\d+)?$')
O después de crear el analizador, podría establecer parser._negative_number_matcher
a este valor. Este enfoque puede tener problemas si está creando grupos o subparsers, pero debería funcionar con un analizador simple.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-16 03:41:48
Aquí está el código que uso. (Es similar a jeremiahbuddha, pero responde a la pregunta más directamente, ya que se trata de números negativos.)
Pon esto antes de llamar argparse.ArgumentParser()
for i, arg in enumerate(sys.argv):
if (arg[0] == '-') and arg[1].isdigit(): sys.argv[i] = ' ' + arg
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-30 02:36:14
Otra solución es pasar el argumento usando '=
' símbolo además de citar el argumento - es decir, --xlim="-2.3e14"
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-09 18:06:26
Inspirado por el enfoque de andrewfn, creé una función auxiliar separada para hacer el sys.argv
jugueteo:
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]
La expresión regular 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 que coincida con el exponente marcador
re.I
hace que coincida con -2e-5
y -2E-5
. Usar p.match
significa que solo busca desde el comienzo de cada cadena.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-24 04:45:48
Si especifica el valor de su opción con un signo igual, argparse
no la 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 en él, puede soltar las comillas:
./blaa.py --xlim=-0.002
Véase: https://www.gnu.org/software/guile/manual/html_node/Command-Line-Format.html
Con esto, no hay necesidad de escribir su propio analizador type=
o redefinir el carácter de prefijo de -
a @
como la respuesta aceptada sugerir.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-02 00:19:39