有些代码行值一千字。使用以下命令创建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) |
然后,在终端中:
给予0,同时:
给0.333333333。我认为这是因为argparse似乎没有将default的论点强制转换成它们的适当类型(所以1在default=1中仍然是int的论点,尽管type=float是这样的,但如果给出了明确的论点,它就会强制转换。
我认为这是不一致的,容易出错。有没有理由让argparse这样做?
- 您正在决定默认值。保持一致是你的责任。为什么python应该质疑您的决定?命令行上没有提供任何值,您已经提供了一个默认值,为什么python应该通过一些函数来过滤它?如果您的意思是使用False作为默认值呢?
- @死亡,我不是说应该有过滤,而是一个隐含的演员。如果我决定把False作为默认参数,它应该转换成0.0。当然,这只是我的意见。我愿意接受为argparse目前的行为辩护的论据。
- 为什么投反对票?请留下评论。
- 这就是我的论点:argparse不应该进一步修改您决定的默认值。因为这会限制你的能力。type表示通过此函数过滤任何输入,但在没有输入时不适用,因为您已经完全控制了默认值,不需要进一步对其进行消毒。
- 默认值=1.0不起作用?
- @deceze我尝试使用"1.0"(字符串)而不是1作为默认值,它确实将其转换为float,所以我认为这涉及到一些转换。不知道为什么不转换1。
- @你是的,当然。重点是,不应该明显地使用$default=1,因为它可能会导致错误,如我的示例所示。
其他答案是正确的——只有字符串默认值通过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)功能混淆。后者返回值,如int、str、bool。另外,最常见的例子是int和float。但在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函数传递每个默认值,那么很难将None或False等值放入namespace中。没有内置函数将字符串转换为None。
关键是,type参数是一个函数(callable而不是一个投射操作或目标。
为了进一步澄清或混淆,请使用nargs=2或action='append'探索default和type。
type的目的是对从命令行接收到的任意输入进行消毒和验证。这是对虚假输入的第一道防线。没有必要"保护"自己不受default价值的影响,因为这是你自己决定的价值,而且你有权并且完全控制你的申请。type并不意味着parse_args()之后的结果值必须是该类型;它意味着任何输入都应该是该类型/应该是该函数的结果。
默认值完全独立于此,完全由您决定。完全可以想象,default值为False,如果用户为这个可选参数输入一个数字,那么它将是一个数字。
将下面的评论升级到这里:python的理念包括"每个人都是负责任的成年人,python不会过度质疑你的决定"(意译)。我想这很适用。
argparse确实转换了default字符串,这一事实可以解释为cli输入始终是一个字符串,并且可能链接了几个argparsers,并且default值是由以前的输入设置的。但是,任何不是字符串类型的内容都必须由您显式选择,这样它就不会被进一步破坏。
- 我不同意。请看我的答案。我在argparse源代码中发现它确实试图确保默认值符合类型。
- …在某种程度上是这样的。如果您愿意,您仍然可以使用False作为默认值(例如…
- 所以有时候是这样,有时候不是。这似乎不一致。我认为如果它总是转换为显式类型的话会更简单。
- @Becko你最好的办法是提交一份bug报告,然后问问作者自己。不确定这是不是故意的
- 在我看来,这至少部分可以追溯到Python的"每个人都是负责任的成年人,Python不会过度质疑你的决定"(意译)。@Becko字符串的例外可能来自这样一个事实,即cli输入始终是字符串类型,并且您可能正在将一组argparsers链接在一起,默认值可能来自以前的argparse,而不是字符串的任何内容都必须由您显式设置。
- @去死吧,这听起来似乎是合理的。)
我认为当调用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) |
不确定这是错误还是妥协…
- 这就是我的观点。我认为,为了保持一致性,您应该在argparse中执行类似于x = float(x)的操作。否则,我上面描述的情况可能导致难以捕捉的错误。
- 其中,float当然是指type=float规范中明确给出给argparse的类型。
- @贝科,你走!我现在明白了。更新!
- 在这条线上的行动是非常有意的。只有字符串值通过type函数传递。在此上下文中,float是一个转换字符串的函数。