【问题标题】:Python argparse - different sets of optionsPython argparse - 不同的选项集
【发布时间】:2017-05-24 05:51:33
【问题描述】:

我有一个名为 program.py 的程序,我正在使用 argparse 进行参数解析。

我想用两种模式运行这个二进制文件: 1) 模拟,不需要参数 2) 非模拟,需要很多参数

我希望程序要么接受

python program --simulation

python program arg1 arg2 arg3 arg4

所有“参数”都是必需的。

我认为这样做的唯一方法是在所有字段中添加“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

【问题讨论】:

  • 您对type=bool 的使用存在问题。请参阅我的答案中的链接。

标签: python command-line argparse


【解决方案1】:

argparse 不可能那么聪明。但是,在您的简单情况下,您可以“帮助”它选择正确的解析选项:

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

【讨论】:

  • 工作得很好,谢谢!一个简单的问题,是否有必要为“get_args”提供“args”?或者这只是为了让它更通用,以防我们想从文本文件中读取参数?
  • 没错,看我的编辑。不传递参数与之前的行为相同:从命令行解析。
【解决方案2】:

对于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 消息对于您的规范来说会很尴尬。

我跳过了你的arg1type=bool 不是有效的 type 参数。在Parsing boolean values with argparse查看我的解释

我将--simulation 更改为store_true,因为您说它没有任何参数。这是接受真假的正常方式。

子解析器通常是接受不同参数模式的最佳工具。在这种情况下,您可以有一个不需要任何参数的名为“simulate”的子解析器,以及另一个需要 4 个位置的调用“somethingelse”。

我将建议一个带有 --simulation--other 选项的互斥组。但是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 值为“?”,否则需要位置参数要么 '*'。您不能为位置提供“必需”参数。

【讨论】:

    【解决方案3】:

    一个稍微简单的方法,假设你很乐意在给定 --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)
    

    【讨论】:

      猜你喜欢
      • 2020-10-12
      • 2013-07-06
      • 2016-08-11
      • 2017-03-12
      • 1970-01-01
      • 2016-03-24
      • 2013-12-21
      • 2021-08-05
      • 1970-01-01
      相关资源
      最近更新 更多