基于另一个参数向argparse添加参数的Python方法

时间:2019-11-28 10:42:48

标签: python argparse

在主函数中,我有一个解析器,用于验证可选输入:

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--platform',required=True)
    parser.add_argument('--foo')
    parser.add_argument('--bar')
    parser.add_argument('--baz')
    parser.parse_args()

上面的代码段是一个示例,仅当我提供-platform -foo -bar 或< em>-baz 。

此代码由不同的组件使用,我们称它们为 A B C

组件 A 实际上仅指定-foo -bar

python script.py --platform A --foo first_example --bar first_example

组件 B 实际上仅指定-bar -baz

python script.py --platform B --bar second_example --baz second_exmaple

组件 C 实际上仅指定-baz

python script.py --platform C --baz third_example

随着我介绍更多提供不同参数的组件,我必须添加到解析器的参数数量增加了。以上只是一个例子,我目前正在处理20左右的论点(将来可能会更多)。

我一直在考虑拥有一个配置文件(.yaml),在其中定义每个组件需要哪些参数:

# parameters.yaml
A:
  - foo
  - bar

B:
  - bar
  - baz

C:
  - baz

我想简化主要功能以查看-platform 参数,并基于已将哪个平台作为参数传递,读取配置并将其他参数添加到解析器。 / p>

这是我尝试过的:

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--platform',required=True)

    # Read from .yaml file
    with open('parameters.yaml') as parameter_file:
        parameters = yaml.safe_load(parameter_file)

    for argument in parameters[sys.argv[sys.argv.index('--platform') + 1]]:
        parser.add_argument(
           '--' + argument
    )

    parser.parse_args()

调用函数:

python script.py --platform C --baz third_example

上面的代码可以工作,但是由于我是Python的初学者,因此我正在寻找其他Pythonic解决方案。一世 不需要查看 sys.argv 来确定已指定了什么-platform 。有没有更好的解决方案来解决这个问题?

2 个答案:

答案 0 :(得分:2)

使用子解析器作为子命令:

import argparse

def run_command(parser, args):
    if args.command == 'A':
        print(args)
    elif args.command == 'B':
        print(args)
    elif args.command == 'C':
        print(args)

parser = argparse.ArgumentParser(
    prog='PROG', 
    epilog="See '<command> --help' to read about a specific sub-command."
)
subparsers = parser.add_subparsers(dest='command', help='Sub-commands')

A_parser = subparsers.add_parser('A', help='Platform A')
A_parser.add_argument("--foo")
A_parser.add_argument('--bar')
A_parser.set_defaults(func=run_command)

B_parser = subparsers.add_parser('B', help='Platform B')
B_parser.add_argument('--bar')
B_parser.add_argument('--baz')
B_parser.set_defaults(func=run_command)

C_parser = subparsers.add_parser('C', help='Platform C')
C_parser.add_argument('--baz')
C_parser.set_defaults(func=run_command)

args = parser.parse_args()
if args.command is not None:
    args.func(parser, args)
else:
    parser.print_help()

这将生成:

~ python args.py -h
usage: PROG [-h] {A,B,C} ...

positional arguments:
  {A,B,C}     Sub-commands
    A         Platform A
    B         Platform B
    C         Platform C

optional arguments:
  -h, --help  show this help message and exit

See '<command> --help' to read about a specific sub-command.

~ python args.py B -h
usage: PROG B [-h] [--bar BAR] [--baz BAZ]

optional arguments:
  -h, --help  show this help message and exit
  --bar BAR
  --baz BAZ

答案 1 :(得分:1)

使用断言。

如果要禁止某些参数,可以添加assert。示例:

parser = argparse.ArgumentParser()
parser.add_argument('--platform',required=True)
parser.add_argument('--foo')
parser.add_argument('--bar')
parser.add_argument('--baz')
args = parser.parse_args()

if args.platform == 'A':
    assert args.baz is None, "no argument baz for the platform A"
...

使用del

使用del排除不需要的参数:

parser = argparse.ArgumentParser()
parser.add_argument('--platform',required=True)
parser.add_argument('--foo')
parser.add_argument('--bar')
parser.add_argument('--baz')
args = parser.parse_args()

if args.platform == 'A':
    del args.baz
...

我不建议您在同一脚本中使用argparsesys.argv,因为在您的情况下它们是出于相同的目的。最好选择其中之一。

argparge在脚本知道值之前解析参数。因此,您不能根据其中一个参数的值来更改参数列表。因此,如果要保留argparse,则必须将整个参数集与.add_argument相加,并在获得值时在下面做一些额外的事情。