35

我有一个小问题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])

虽然我可以让它以这种方式工作,但我真的更愿意使用科学记数法。有人有想法么?

干杯

4

7 回答 7

40

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

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

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

于 2013-06-21T13:13:45.680 回答
16

As already pointed out by the comments, the problem is that a - prefix is parsed as an option instead of as an argument. One way to workaround this is change the prefix used for options with prefix_chars argument:

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

Example output:

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

Edit: Alternatively, you can keep using - as separator, pass xlim as a single value and use a function in type to implement your own parsing:

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

Example output:

$ ./blaa.py --xlim "-2e-3 1e4"
Namespace(xlim=[-0.002, 10000.0])
于 2012-01-27T09:37:00.443 回答
14

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

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

如果该值中没有空格(或给您的 shell 的其他特殊字符),您可以删除引号:

./blaa.py --xlim=-0.002

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

有了这个,就不需要编写自己的type=解析器或重新定义前缀字符 from -to ,@正如接受的答案所暗示的那样。

于 2018-03-02T00:19:39.250 回答
9

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

在打电话之前放这个argparse.ArgumentParser()

for i, arg in enumerate(sys.argv):
  if (arg[0] == '-') and arg[1].isdigit(): sys.argv[i] = ' ' + arg
于 2014-01-30T02:36:14.283 回答
7

另一个解决方法是=除了引用参数外,还使用“ ”符号传入参数 - 即,--xlim="-2.3e14"

于 2014-12-09T17:43:31.190 回答
4

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

class _ActionsContainer.__init__()

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

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

于 2013-03-15T06:22:05.710 回答
3

受 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-2or -4354.5e-6
  • \\.?:一个可选的时期(例如,-2e-5是合理的)
  • \\d*-2e-5:另一组零个或多个数字(用于和之类的东西-7.e-3
  • e: 匹配指数标记

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

于 2016-10-24T04:45:48.767 回答