Python Argparse:处理负数可选参数的问题

43 投票
7 回答
22305 浏览
提问于 2025-04-17 11:10

我在使用 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 个回答

17

如果你用等号给选项指定了一个值,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= 的解析器,也不需要像接受的答案中提到的那样,把前缀字符从 - 改成 @

52

我找到的一个解决办法是把值用引号括起来,但要加一个空格。也就是说,

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

这样做的话,argparse就不会把-2.e-3当成一个选项名称,因为第一个字符不是连字符(-),但它仍然会被正确转换成浮点数,因为float(string)会忽略左边的空格。

19

正如评论中提到的,问题在于一个 - 符号前缀被当作选项来解析,而不是作为一个参数。解决这个问题的一种方法是使用 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])

撰写回答