Python argparse - 不同的选项集
Python argparse - different sets of options
我有一个名为 program.py 的程序,我正在使用 argparse 进行参数解析。
我有两种模式想要 运行 这个二进制文件:
1)模拟,不需要参数
2) 非模拟,需要很多参数
我希望程序接受
python program --simulation
或
python program arg1 arg2 arg3 arg4
其中所有 'args' 都是必需的。
我想这样做的唯一方法是在所有字段中添加'required = False'并手动检查逻辑,但我想知道是否有更优雅的方法。
这是我的代码的精简版
def get_args():
parser = argparse.ArgumentParser(description = "program")
parser.add_argument("arg1", type = bool)
parser.add_argument("arg2" ,type = str)
parser.add_argument("arg3", type = int)
parser.add_argument("arg4", type = str)
parser.add_argument("--simulation")
args = parser.parse_args()
return args
argparse
不可能那么聪明。但是,在您的简单情况下,您可以 "help" 它来选择正确的解析选项:
def get_args(args=sys.argv[1:]):
parser = argparse.ArgumentParser(description = "program")
if args and args[0].startswith("--"):
parser.add_argument("--simulation")
else:
parser.add_argument("arg1", type = bool)
parser.add_argument("arg2" ,type = str)
parser.add_argument("arg3", type = int)
parser.add_argument("arg4", type = str)
args = parser.parse_args(args=args)
return args
所以 print(get_args("--simulation xx".split()))
产量:
Namespace(simulation='xx')
因为第一个参数以 --
开头。任何其他选项都无法按预期进行命令行解析。
和 print(get_args("True foo 3 bar".split()))
产量:
Namespace(arg1=True, arg2='foo', arg3=3, arg4='bar')
忘记 4 个位置参数之一无法按预期进行命令行解析。
顺便说一句,我添加了一个默认参数,如果省略它,它会从系统参数中读取(就像在您的代码中所做的那样)。否则您可以从文本文件中读取并传递 args 标记。因此更容易测试和创建可以使用其他模块的参数调用的模块,而无需破解 sys.argv
.
这对于 argparse
来说显然是一个尴尬的规范,我怀疑大多数其他 POSIX 风格的解析器。
扫描 sys.argv
并调整解析器定义是一种可能的方法。
另一种是使用 2 阶段解析器,parse_known_args
:
import argparse
usage = 'prog [-h] [--simulation] [arg1 arg2 arg3 arg4]'
parser1 = argparse.ArgumentParser(usage=usage)
parser1.add_argument('--simulation', action='store_true')
# or omit the `store_true` if it just takes one argument
# other possible optionals
parser2 = argparse.ArgumentParser()
#parser2.add_argument("arg1", type = bool) # not a valid type parameter
parser2.add_argument("arg2" )
parser2.add_argument("arg3", type = int)
parser2.add_argument("arg4")
# positionals are required, unless nargs=? or *
args, extras = parser1.parse_known_args()
if not args.simulation:
args = parser2.parse_args(extras, namespace=args)
elif extras:
parser1.error('cannot use --simulation with args')
print(args)
可能的运行包括:
1526:~/mypy$ python stack41556997.py -h
usage: prog [-h] [--simulation] [arg1 arg2 arg3 arg4]
optional arguments:
-h, --help show this help message and exit
--simulation
1526:~/mypy$ python stack41556997.py --simulation
Namespace(simulation=True)
1527:~/mypy$ python stack41556997.py 1 2 3
Namespace(arg2='1', arg3=2, arg4='3', simulation=False)
1527:~/mypy$ python stack41556997.py 1 2 3 --sim
usage: prog [-h] [--simulation] [arg1 arg2 arg3 arg4]
stack41556997.py: error: cannot use --simulation with args
请注意,帮助不包括这两套。我在自定义用法中包含了一些信息,但是 arg#
没有帮助行。生成良好的 help
消息将与您的规范不符。
我跳过了你的arg1
。 type=bool
不是有效的 type
参数。在 Parsing boolean values with argparse
查看我的解释
我将 --simulation
更改为 store_true
因为你说它没有任何参数。这是接受 True/False.
的正常方式
子解析器通常是接受不同参数模式的最佳工具。在这种情况下,您可以有一个不需要任何参数的名为 'simulate' 的子解析器,以及另一个需要 4 个位置的调用 'somethingelse'。
我打算建议一个带有 --simulation
和 --other
选项的 mutually_exclusive_group。但是 store_true
的论点在这样的群体中是行不通的。
=============
子解析器路由:
parser = argparse.ArgumentParser()
sp = parser.add_subparsers(dest='cmd')
sp.add_parser('simulate')
parser2 = sp.add_parser('other')
parser2.add_argument("arg2" )
parser2.add_argument("arg3", type = int)
parser2.add_argument("arg4")
print(parser.parse_args())
测试:
1552:~/mypy$ python stack41556997.py -h
usage: stack41556997.py [-h] {simulate,other} ...
positional arguments:
{simulate,other}
optional arguments:
-h, --help show this help message and exit
1557:~/mypy$ python stack41556997.py simulate
Namespace(cmd='simulate')
1557:~/mypy$ python stack41556997.py other -h
usage: stack41556997.py other [-h] arg2 arg3 arg4
positional arguments:
arg2
arg3
arg4
optional arguments:
-h, --help show this help message and exit
1557:~/mypy$ python stack41556997.py other 1 2 3
Namespace(arg2='1', arg3=2, arg4='3', cmd='other')
请注意,arg3
type
将输入转换为整数。其他的保留为字符串。通过此设置,args.cmd
将成为子解析器的名称,与布尔 args.simulation
属性不太一样。
==================
默认情况下不需要标记的参数。位置参数是必需的,除非 nargs
值为 '?'要么 '*'。您不能为位置提供 'required' 参数。
一个稍微简单的方法,假设你很乐意在给定 --simulation
参数时忽略任何额外的参数,是这样的:
parser = argparse.ArgumentParser(description = "program")
parser.add_argument("arg1", type = bool)
parser.add_argument("arg2" ,type = str)
parser.add_argument("arg3", type = int)
parser.add_argument("arg4", type = str)
parser.add_argument("--simulation")
if "--simulation" in sys.argv:
simulation()
else:
args = parser.parse_args()
main(args)
我有一个名为 program.py 的程序,我正在使用 argparse 进行参数解析。
我有两种模式想要 运行 这个二进制文件: 1)模拟,不需要参数 2) 非模拟,需要很多参数
我希望程序接受
python program --simulation
或
python program arg1 arg2 arg3 arg4
其中所有 'args' 都是必需的。
我想这样做的唯一方法是在所有字段中添加'required = False'并手动检查逻辑,但我想知道是否有更优雅的方法。
这是我的代码的精简版
def get_args():
parser = argparse.ArgumentParser(description = "program")
parser.add_argument("arg1", type = bool)
parser.add_argument("arg2" ,type = str)
parser.add_argument("arg3", type = int)
parser.add_argument("arg4", type = str)
parser.add_argument("--simulation")
args = parser.parse_args()
return args
argparse
不可能那么聪明。但是,在您的简单情况下,您可以 "help" 它来选择正确的解析选项:
def get_args(args=sys.argv[1:]):
parser = argparse.ArgumentParser(description = "program")
if args and args[0].startswith("--"):
parser.add_argument("--simulation")
else:
parser.add_argument("arg1", type = bool)
parser.add_argument("arg2" ,type = str)
parser.add_argument("arg3", type = int)
parser.add_argument("arg4", type = str)
args = parser.parse_args(args=args)
return args
所以 print(get_args("--simulation xx".split()))
产量:
Namespace(simulation='xx')
因为第一个参数以 --
开头。任何其他选项都无法按预期进行命令行解析。
和 print(get_args("True foo 3 bar".split()))
产量:
Namespace(arg1=True, arg2='foo', arg3=3, arg4='bar')
忘记 4 个位置参数之一无法按预期进行命令行解析。
顺便说一句,我添加了一个默认参数,如果省略它,它会从系统参数中读取(就像在您的代码中所做的那样)。否则您可以从文本文件中读取并传递 args 标记。因此更容易测试和创建可以使用其他模块的参数调用的模块,而无需破解 sys.argv
.
这对于 argparse
来说显然是一个尴尬的规范,我怀疑大多数其他 POSIX 风格的解析器。
扫描 sys.argv
并调整解析器定义是一种可能的方法。
另一种是使用 2 阶段解析器,parse_known_args
:
import argparse
usage = 'prog [-h] [--simulation] [arg1 arg2 arg3 arg4]'
parser1 = argparse.ArgumentParser(usage=usage)
parser1.add_argument('--simulation', action='store_true')
# or omit the `store_true` if it just takes one argument
# other possible optionals
parser2 = argparse.ArgumentParser()
#parser2.add_argument("arg1", type = bool) # not a valid type parameter
parser2.add_argument("arg2" )
parser2.add_argument("arg3", type = int)
parser2.add_argument("arg4")
# positionals are required, unless nargs=? or *
args, extras = parser1.parse_known_args()
if not args.simulation:
args = parser2.parse_args(extras, namespace=args)
elif extras:
parser1.error('cannot use --simulation with args')
print(args)
可能的运行包括:
1526:~/mypy$ python stack41556997.py -h
usage: prog [-h] [--simulation] [arg1 arg2 arg3 arg4]
optional arguments:
-h, --help show this help message and exit
--simulation
1526:~/mypy$ python stack41556997.py --simulation
Namespace(simulation=True)
1527:~/mypy$ python stack41556997.py 1 2 3
Namespace(arg2='1', arg3=2, arg4='3', simulation=False)
1527:~/mypy$ python stack41556997.py 1 2 3 --sim
usage: prog [-h] [--simulation] [arg1 arg2 arg3 arg4]
stack41556997.py: error: cannot use --simulation with args
请注意,帮助不包括这两套。我在自定义用法中包含了一些信息,但是 arg#
没有帮助行。生成良好的 help
消息将与您的规范不符。
我跳过了你的arg1
。 type=bool
不是有效的 type
参数。在 Parsing boolean values with argparse
我将 --simulation
更改为 store_true
因为你说它没有任何参数。这是接受 True/False.
子解析器通常是接受不同参数模式的最佳工具。在这种情况下,您可以有一个不需要任何参数的名为 'simulate' 的子解析器,以及另一个需要 4 个位置的调用 'somethingelse'。
我打算建议一个带有 --simulation
和 --other
选项的 mutually_exclusive_group。但是 store_true
的论点在这样的群体中是行不通的。
=============
子解析器路由:
parser = argparse.ArgumentParser()
sp = parser.add_subparsers(dest='cmd')
sp.add_parser('simulate')
parser2 = sp.add_parser('other')
parser2.add_argument("arg2" )
parser2.add_argument("arg3", type = int)
parser2.add_argument("arg4")
print(parser.parse_args())
测试:
1552:~/mypy$ python stack41556997.py -h
usage: stack41556997.py [-h] {simulate,other} ...
positional arguments:
{simulate,other}
optional arguments:
-h, --help show this help message and exit
1557:~/mypy$ python stack41556997.py simulate
Namespace(cmd='simulate')
1557:~/mypy$ python stack41556997.py other -h
usage: stack41556997.py other [-h] arg2 arg3 arg4
positional arguments:
arg2
arg3
arg4
optional arguments:
-h, --help show this help message and exit
1557:~/mypy$ python stack41556997.py other 1 2 3
Namespace(arg2='1', arg3=2, arg4='3', cmd='other')
请注意,arg3
type
将输入转换为整数。其他的保留为字符串。通过此设置,args.cmd
将成为子解析器的名称,与布尔 args.simulation
属性不太一样。
==================
默认情况下不需要标记的参数。位置参数是必需的,除非 nargs
值为 '?'要么 '*'。您不能为位置提供 'required' 参数。
一个稍微简单的方法,假设你很乐意在给定 --simulation
参数时忽略任何额外的参数,是这样的:
parser = argparse.ArgumentParser(description = "program")
parser.add_argument("arg1", type = bool)
parser.add_argument("arg2" ,type = str)
parser.add_argument("arg3", type = int)
parser.add_argument("arg4", type = str)
parser.add_argument("--simulation")
if "--simulation" in sys.argv:
simulation()
else:
args = parser.parse_args()
main(args)