我和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])
虽然我可以通过这种方式使用它,但我真的宁愿能够使用科学记数法。有人有主意吗?
干杯
正如评论已经指出的那样,问题是-
前缀被解析为一个选项而不是一个参数。解决此问题的一种方法是使用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])
我发现的一个解决方法是引用值,但添加一个空格。那是,
./blaa.py --xlim " -2.e-3" 1e4
这样argparse就不会认为-2.e-3是一个选项名称,因为第一个字符不是连字符破折号,但它仍然可以正确转换为浮点数,因为float(string)会忽略左边的空格。
这是我使用的代码。 (它类似于jeremiahbuddha,但它更直接地回答了这个问题,因为它处理负数。)
在调用argparse.ArgumentParser()
之前说出来
for i, arg in enumerate(sys.argv):
if (arg[0] == '-') and arg[1].isdigit(): sys.argv[i] = ' ' + arg
另一个解决方法是使用'=
'符号传入参数,除了引用参数 - 即,--xlim="-2.3e14"
如果您要修改argparse.py
本身,您可以更改负数匹配器以处理科学记数法:
在class _ActionsContainer.__init__()
self._negative_number_matcher = _re.compile(r'^-(\d+\.?|\d*\.\d+)([eE][+\-]?\d+)?$')
或者在创建解析器之后,您可以将parser._negative_number_matcher
设置为此值。如果要创建组或子分析器,此方法可能会出现问题,但应该使用简单的解析器。
如果您使用等号指定选项的值,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=
解析器或重新定义从-
到@
的前缀字符,如接受的答案所示。
受到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
意味着它只从每个字符串的开头搜索。