Python Argparse:带有可选参数的问题是负数

时间:2012-01-26 20:55:56

标签: python argparse negative-number

argparse我遇到了一个小问题。我有一个选项xlim,它是一个情节的xrange。我希望能够传递-2e-5之类的数字。但是这不起作用 - argparse解释这是一个位置参数。如果我-0.00002它有效:argparse将其作为负数读取。是否可以阅读-2e-3

代码如下,我将如何运行它的一个例子是:

./blaa.py --xlim -2.e-3 1e4 

如果我执行以下操作,则可以:

./blaa.py --xlim -0.002 1e4 

代码:

parser.add_argument('--xlim', nargs = 2,
                  help = 'X axis limits',
                  action = 'store', type = float, 
                  default = [-1.e-3, 1.e-3])

虽然我可以通过这种方式使用它,但我真的宁愿能够使用科学记数法。有人有什么想法吗?

干杯

7 个答案:

答案 0 :(得分:28)

我发现的一个解决方法是引用该值,但添加一个空格。也就是说,

./blaa.py --xlim " -2.e-3" 1e4

这样argparse不会认为-2.e-3是一个选项名称,因为第一个字符不是连字符破折号,但它仍然可以正确转换为浮点数,因为float(string)忽略了左

答案 1 :(得分:11)

正如评论已经指出的那样,问题是-前缀被解析为一个选项而不是一个参数。解决此问题的一种方法是使用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()

示例输出:

$ ./blaa.py @@xlim -2.e-3 1e4
Namespace(xlim=[-0.002, 10000.0])

编辑:或者,您可以继续使用-作为分隔符,将xlim作为单个值传递,并使用type中的函数来实现您自己的解析:

#!/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()

示例输出:

$ ./blaa.py --xlim "-2e-3 1e4"
Namespace(xlim=[-0.002, 10000.0])

答案 2 :(得分:5)

这是我使用的代码。 (它类似于jeremiahbuddha'但它更直接地回答了这个问题,因为它处理的是负数。)

在致电argparse.ArgumentParser()

之前先把它放好
for i, arg in enumerate(sys.argv):
  if (arg[0] == '-') and arg[1].isdigit(): sys.argv[i] = ' ' + arg

答案 3 :(得分:5)

另一种解决方法是使用' ='传递参数。除了引用参数之外的符号 - 即--xlim="-2.3e14"

答案 4 :(得分:4)

如果您要修改argparse.py本身,可以更改负数匹配器以处理科学记数法:

class _ActionsContainer.__init__()

self._negative_number_matcher = _re.compile(r'^-(\d+\.?|\d*\.\d+)([eE][+\-]?\d+)?$')

或者在创建解析器之后,您可以将parser._negative_number_matcher设置为此值。如果要创建组或子分析器,这种方法可能会出现问题,但是应该使用简单的解析器。

答案 5 :(得分:3)

如果您使用等号指定选项的值,argparse将不会将其视为单独的选项,即使它以-开头:

./blaa.py --xlim='-0.002 1e4'
# As opposed to --xlim '-0.002 1e4'

如果值中没有空格,则可以删除引号:

./blaa.py --xlim=-0.002

请参阅:https://www.gnu.org/software/guile/manual/html_node/Command-Line-Format.html

有了这个,就没有必要编写自己的type=解析器,或者根据接受的答案建议,将-中的前缀字符重新定义为@

答案 6 :(得分:1)

受到andrewfn方法的启发,我创建了一个单独的辅助函数来执行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]

正则表达式寻找:

  • -:负号
  • \\d*:零个或多个数字(对于奇怪格式化的值,如-.5e-2-4354.5e-6
  • \\.?:可选期间(例如,-2e-5合理)
  • \\d*:另一组零或多位数字(适用于-2e-5-7.e-3
  • e:匹配指数标记

re.I使其与-2e-5-2E-5都匹配。使用p.match意味着它只从每个字符串的开头搜索。