关于python:argparse不会转换默认的数字参数?

argparse doesn't cast default numeric arguments?

有些代码行值一千字。使用以下命令创建python文件test.py

1
2
3
4
5
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--G', type=float, default=1, nargs='?')
args = parser.parse_args()
print (args.G / 3)

然后,在终端中:

1
python test.py

给予0,同时:

1
python test.py --G 1

0.333333333。我认为这是因为argparse似乎没有将default的论点强制转换成它们的适当类型(所以1default=1中仍然是int的论点,尽管type=float是这样的,但如果给出了明确的论点,它就会强制转换。

我认为这是不一致的,容易出错。有没有理由让argparse这样做?


其他答案是正确的——只有字符串默认值通过type函数传递。但似乎有些人不愿意接受这种逻辑。

也许这个例子有助于:

1
2
3
4
5
6
7
8
import argparse
def mytype(astring):
    return '['+astring+']'
parser = argparse.ArgumentParser()
parser.add_argument('--foo', type=mytype, default=1)
parser.add_argument('--bar', type=mytype, default='bar')
print parser.parse_args([])
print mytype(1)

生产:

1
2
3
4
5
6
7
8
0923:~/mypy$ python stack35429336.py
Namespace(bar='[bar]', foo=1)
Traceback (most recent call last):
  File"stack35429336.py", line 8, in <module>
    print mytype(1)
  File"stack35429336.py", line 3, in mytype
    return '['+astring+']'
TypeError: cannot concatenate 'str' and 'int' objects

我定义了一个type函数——它接受一个字符串输入,并返回一些东西——任何我想要的东西。如果不能返回,则会引发错误。在这里,我只是在字符串中附加一些字符。

default是字符串时,它会被修改。但当它是一个数字(而不是字符串)时,它是不加更改地插入的。事实上,如果给定一个数字,mytype就会产生一个错误。

argparsetype常与type(a)功能混淆。后者返回值,如intstrbool。另外,最常见的例子是intfloat。但在argparse中,float用作函数

1
2
float(x) -> floating point number
    Convert a string or number to a floating point number, if possible.

type=bool是一个常见的错误。使用argparse分析布尔值。bool()不将字符串'False'转换为布尔False

1
2
In [50]: bool('False')
Out[50]: True

如果argparse通过type函数传递每个默认值,那么很难将NoneFalse等值放入namespace中。没有内置函数将字符串转换为None

关键是,type参数是一个函数(callable而不是一个投射操作或目标。

为了进一步澄清或混淆,请使用nargs=2action='append'探索defaulttype


type的目的是对从命令行接收到的任意输入进行消毒和验证。这是对虚假输入的第一道防线。没有必要"保护"自己不受default价值的影响,因为这是你自己决定的价值,而且你有权并且完全控制你的申请。type并不意味着parse_args()之后的结果值必须是该类型;它意味着任何输入都应该是该类型/应该是该函数的结果。

默认值完全独立于此,完全由您决定。完全可以想象,default值为False,如果用户为这个可选参数输入一个数字,那么它将是一个数字。

将下面的评论升级到这里:python的理念包括"每个人都是负责任的成年人,python不会过度质疑你的决定"(意译)。我想这很适用。

argparse确实转换了default字符串,这一事实可以解释为cli输入始终是一个字符串,并且可能链接了几个argparsers,并且default值是由以前的输入设置的。但是,任何不是字符串类型的内容都必须由您显式选择,这样它就不会被进一步破坏。


我认为当调用parser.add_argument时,会对default=1中的1进行评估,其中作为参数传递的非默认值在运行时进行评估,因此可以通过argparse转换为float。这不是argparse的行为方式,而是python的一般行为方式。考虑这个

1
2
3
4
5
6
def foo(x=1):
    # there is no way to tell the function body that you want 1.0
    # except for explicitly conversion
    # because 1 is passed by value, which has already been evaluated
    # and determined to be an int
    print (x/3)

大编辑:哈,我现在明白你的观点了,我认为这是合理的。因此,我深入研究源代码,并查看我发现的内容:

https://hg.python.org/cpython/file/3.5/lib/argparse.py l1984

因此,argparse看起来确实可以确保您的默认值是符合类型的,只要它是字符串。尝试:

1
2
3
4
5
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--G', type=float, default='1', nargs='?')
args = parser.parse_args()
print (args.G / 3)

不确定这是错误还是妥协…