如何将Argparse参数的默认值设置为位置参数的值?
我有一个Python脚本,用来发送GET请求。它使用Argparse这个工具来接收三个参数:
- 地址:发送GET请求的目标地址
- 主机:在GET请求中声明的主机名
- 资源:请求的具体资源
一个使用示例可能是:
$ python get.py 198.252.206.16 stackoverflow.com /questions/ask
不过在大多数情况下,其实只需要提供主机和资源,因为主机会自动解析成地址:
$ host -t a stackoverflow.com
stackoverflow.com has address 198.252.206.16
所以理想的使用方式可能是:
$ python get.py stackoverflow.com /questions/ask
我该如何设置Argparse,让地址参数的默认值等于主机参数的值呢?
有人让我展示一下当前解析参数的代码。代码如下:
import argparse
parser = argparse.ArgumentParser(description=
'Send a GET request and obtain the HTTP response header and/or body.')
parser.add_argument("-v", "--verbose",
help="Turn on verbose mode.",
action="store_true")
parser.add_argument("-p", "--port",
type=int,
default=80,
help="Which port to use when sending the GET request."
parser.add_argument("address",
help="Where to send the GET request to.")
parser.add_argument("host",
help="Which Host to declare in the GET request.")
parser.add_argument("resource",
help="Which resource to request.")
parser.parse_args()
3 个回答
这里有两个不错的选择,你可以根据自己对使用位置参数和选项参数的偏好来决定。
添加一个位置参数,使用
nargs='+'
。解析参数后,检查这个列表的长度。如果长度是3,就把它们分别设置为地址、主机和资源。如果长度是2,就把主机和资源设置好,然后把地址从主机复制过来。否则,就打印一个使用说明并抛出一个异常。把主机和资源保留为位置参数,把地址改成一个选项。这意味着命令行的格式会变成这样:
python get.py stackoverflow.com /questions/ask --address 198.252.206.16
你可以把默认值设置为 None
,然后在解析参数后检查它是否为 None。我觉得在 argparse 中没有办法让它自动默认到另一个位置参数。
选择哪个完全是个人喜好,我更喜欢第二种(可选参数本质上就是选项),因为这样更符合工具的使用。如果你强行让 argparse 像第一种那样工作,你还得额外覆盖 --help
选项、使用说明等,因为自动生成的默认值会让人困惑。
如果你想仅仅通过位置参数来实现你描述的功能,可以使用一个列表参数(nargs),像这样:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("args", nargs="+")
parsed = parser.parse_args()
args = parsed.args
if len(args) == 3:
ip, host, address = args
print ip, host, address
elif len(args) == 2:
ip, host, address = args[0], args[0], args[1]
print ip, host, address
else:
print "Invalid args"
不过,这种方法有点不太正规,而且你还会失去 argparse 提供的一些好处(你需要手动检查参数)。我建议你使用可选参数。可以像这样:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-host", required=True)
parser.add_argument("-res", required=True)
parser.add_argument("-ip", required=False)
args = parser.parse_args()
ip = args.ip if args.ip else args.host
print args.host, args.res, ip
然后像这样执行它:
python2.7 test.py -host hello -res world
nargs='?'
很好地处理了这种情况。如果只有两个字符串,它们会被分别赋值给 host
和 resource
,而 address
则会使用默认值(None
)。如果有三个字符串,它们就会分别赋值给这三个变量。如果你觉得这样不太好理解,可以想象一下 ?
在 re
模式中的表现。
在解析器完成后,很容易将 host
的值赋给 address
。在 parse_args
中尝试进行这种赋值是没有意义的,因为此时还不知道 host
的值。
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("address", nargs='?')
parser.add_argument("host")
parser.add_argument("resource")
args = parser.parse_args()
if args.address is None:
args.address = args.host
print(args)
用法是:
usage: get.py [-h] [address] host resource
其中 []
清晰地标记了这个可选的位置参数。