Python argparse 可选参数只有在正确的位置输入时才有效

Python argparse Optional argument only works when it's entered in the right positions

在我的脚本中,我有 3 个位置参数和 1 个可选参数。三个位置参数之一是必需的,其余的是可选的(使用 narg='?' 指定)。

我的可选参数不传递任何其他参数 (action ='store_true'),只是为了启用排序,稍后将实现。

但是,我的问题是我的可选参数只有在它是脚本调用中的第一个或最后一个参数时才有效。

以下是我目前的脚本:

parser = argparse.ArgumentParser()
parser.add_argument("-s", "--sort", help="option to sort the ip addresses", action='store_true')
parser.add_argument("file_name", help="Name of the file containing the tcpdump")
parser.add_argument("source_IP", nargs='?', type=str, help="Source ip to search") 
parser.add_argument("dest_IP", nargs='?', type=str, help="Destination ip to search")

args = parser.parse_args()    

如果我在任何其他位置参数之间输入 -s,我会收到错误消息。

 Ex: ./my_script file.txt -s 192.168.152.32 192.168.0.25

usage: 1 [-h] [-s] file_name [source_IP] [dest_IP]
1: error: unrecognized arguments: 192.168.152.32 192.168.0.25

我的目标是能够在脚本调用的任何位置输入我的可选参数 (-s) 并使其正常工作。

您有三个位置参数,但由于 nargs='?',其中两个也是可选的。 argparse 搞砸了,因为它看到位置文件名,然后必须在将 -s 解释为可选的位置 source 或作为开关之间任意选择。任何一种解释都是有效的(它没有进行复杂的回溯解析来试图找到一些允许它完成的参数的合法解释;对某些参数类型这样做可能会导致非常糟糕的行为,比如打开一个文件,然后回溯,关闭它,然后打开其他东西)。

简短回答:一般来说,可选参数应该全部是位置参数,或者全部是开关参数。混合和匹配引入了复杂性,使解析成为一个复杂的递归过程,只能试探性地猜测正确的解析(特别是 nargs='*'nargs='+',但即使 '?' 也会导致问题,如您所见) .从 sourcedest 中删除 nargs 限定符,或者将它们保留为可选并转换为开关将允许 -s 以您喜欢的任何顺序传递。

这个问题很微妙,需要很好地理解 argparse 如何解析位置变量和可选变量。

如果所有位置都采用一个参数(默认 nargs),那么 -s 可以出现在任何位置 - 开始、结束或任何位置之间。

发生了什么:

./my_script file.txt -s 192.168.152.32 192.168.0.25

是在解析file_name时,source_IPdest_IP都被消耗(并设置为默认值)。然后它处理 -s。现在还剩下 2 个字符串,但没有位置符号来使用它们,因此出现 unrecognized arguments 错误。请注意 ./my_script file.txt./my_script file.txt -s 一样运行良好。在所有 3 种情况下,2 个 IP 参数与 file_name.

同时被消耗

parse_args 在使用位置变量和可选变量之间交替。它会一次消耗与字符串一样多的位置(想想一个贪婪的正则表达式)。由于 source_IPdest_IP 可以使用 0 个参数,所以这三个参数在第一次处理位置时都会被消耗掉。

除了要小心使用 nargs='?' positionals 之外,没有针对用户的完美修复。

有一个 bug/issue 试图解决这个问题。但修复并非易事。解析器必须 'look ahead',注意它可能会延迟解析这些 '?'参数。

http://bugs.python.org/issue15112
argparse: nargs='*' positional argument doesn't accept any items
   if preceded by an option and another positional

您的解析器运行良好,argparse 按照该问题中的建议进行了修补。但是 argparse 的潜在补丁积压很多。