【问题标题】:python - mutually exclusive arguments complains about action indexpython - 互斥参数抱怨动作索引
【发布时间】:2015-05-29 00:41:51
【问题描述】:

我正在尝试对参数进行分组,以便用户可以执行以下任一操作:

python sample.py scan -a 1 -b 2
or
python sample.pt save -d /tmp -n something

这是我的代码:

import argparse
if __name__ == '__main__':
    parser = argparse.ArgumentParser(
            description='this is the description'
            )
    parser.add_argument('op', choices=['scan','save'], help='operation', default='scan')
    root_group = parser.add_mutually_exclusive_group()

    group1 = root_group.add_argument_group('g1', 'scan')
    group1.add_argument('-a', help='dir1')
    group1.add_argument('-b', help='dir2')

    group2 = root_group.add_argument_group('g2', 'save')
    group2.add_argument('-d', help='dir')
    group2.add_argument('-n', help='name')

    args = parser.parse_args()
    print args

当我运行 python sample.py --help

我遇到了一个错误。谁能告诉我如何解决它?

Traceback (most recent call last):
  File "sample.py", line 18, in <module>
    args = parser.parse_args()
  File "C:\Python27\lib\argparse.py", line 1688, in parse_args
    args, argv = self.parse_known_args(args, namespace)
  File "C:\Python27\lib\argparse.py", line 1720, in parse_known_args
    namespace, args = self._parse_known_args(args, namespace)
  File "C:\Python27\lib\argparse.py", line 1926, in _parse_known_args
    start_index = consume_optional(start_index)
  File "C:\Python27\lib\argparse.py", line 1866, in consume_optional
    take_action(action, args, option_string)
  File "C:\Python27\lib\argparse.py", line 1794, in take_action
    action(self, namespace, argument_values, option_string)
  File "C:\Python27\lib\argparse.py", line 994, in __call__
    parser.print_help()
  File "C:\Python27\lib\argparse.py", line 2313, in print_help
    self._print_message(self.format_help(), file)
  File "C:\Python27\lib\argparse.py", line 2287, in format_help
    return formatter.format_help()
  File "C:\Python27\lib\argparse.py", line 279, in format_help
    help = self._root_section.format_help()
  File "C:\Python27\lib\argparse.py", line 209, in format_help
    func(*args)
  File "C:\Python27\lib\argparse.py", line 317, in _format_usage
    action_usage = format(optionals + positionals, groups)
  File "C:\Python27\lib\argparse.py", line 388, in _format_actions_usage
    start = actions.index(group._group_actions[0])
IndexError: list index out of range

如果我添加 action='store_const',错误就会消失,并且会出现一个新的错误,要求输入 4 个。

【问题讨论】:

  • -d-n中删除required=True
  • 那行不通。避免它的唯一方法是指定操作,但随后会出现另一个错误。
  • 据我所知, add_mutually_exclusive_group() 只接受一个布尔参数。你检查过函数的定义吗? docs.python.org/3.4/library/argparse.html#mutual-exclusion
  • 是的。在发布之前我已经阅读了 python 文档。
  • 对不起,我的意思是把'g1'放在组参数中......仍然存在问题。

标签: python argparse


【解决方案1】:

Argparse 似乎不完全支持将一个组添加到另一个组中。发生此错误是因为 Argparse 需要 root_group 进行某种操作。一种解决方法是向组中添加一个参数:

import argparse

if __name__ == '__main__':
    parser = argparse.ArgumentParser(
            description='this is the description'
            )

    # This is now redundant. We can remove it
    # parser.add_argument('op', choices=['scan','save'], help='operation', default='scan')
    root_group = parser.add_mutually_exclusive_group()

    # Workaround
    root_group.add_argument('--scan', help='scan', action='store_true')
    root_group.add_argument('--save', help='save', action='store_true')

    group1 = root_group.add_argument_group('g1', 'scan')
    group2 = root_group.add_argument_group('g2', 'save')

    group1.add_argument('-a', help='dir1')
    group1.add_argument('-b', help='dir2')

    group2.add_argument('-d', help='dir', default='')
    group2.add_argument('-n', help='name')

    args = parser.parse_args()
    print args 

请注意,我们使用的是 --scan--save。为避免使用-- 前缀,您可能需要Sub-commands 的帮助。详情可见here

【讨论】:

    【解决方案2】:

    感谢上面@skyline 的链接,我可以使用子解析器:

    import argparse
    if __name__ == '__main__':
        parser = argparse.ArgumentParser(
                description='this is the description'
                )
    
        scan_parser = argparse.ArgumentParser(add_help=False)
        scan_parser.add_argument('-a', '--a', help='first num', required=True)
        scan_parser.add_argument('-b', '--b', help='second num', required=True)
    
        save_parser = argparse.ArgumentParser(add_help=False)
        save_parser.add_argument('-d', '--d', help='directory path', required=True)
        save_parser.add_argument('-n', '--n', help='name of the file', required=True)
    
        sp = parser.add_subparsers()
    
        sp_scan = sp.add_parser('scan', parents=[scan_parser], help='scans directories')
        sp_save = sp.add_parser('save', parents=[save_parser], help='saves something')
        args = parser.parse_args()
        print args
    

    【讨论】:

    • 如果您将此答案标记为已接受,将阻止其他人尝试回答您的问题;)
    【解决方案3】:

    格式化usage 行时发生错误,这是root_group 没有任何_group_actions 的结果。我从其他错误问题中知道使用格式化程序很脆弱。

    argument_groupsmutually_exclusive_groups 不是为嵌套而设计的。尽管名称(和阶级传统)相似,但它们的用途却截然不同。 argument_groups 控制help 行的显示。 mutually_exclusive_groups 控制使用显示,并引发错误。

    在您的情况下,添加到 group1group2 的参数已添加到主解析器列表中,但未添加到 root_group 用于排他性检查(或使用格式)的列表中。

    如果我直接向root_group 添加一个参数,help 会起作用并产生:

    In [19]: parser.print_help()
    usage: ipython3 [-h] [-a A] [-b B] [-d D] [-n N] [--foo FOO] {scan,save}
    
    this is the description
    
    positional arguments:
      {scan,save}  operation
    
    optional arguments:
      -h, --help   show this help message and exit
      --foo FOO
    

    您可以从“相关”侧边栏中看到,许多人询问有关向 mutually_exclusive_groups 添加参数组的问题。一个允许嵌套组具有各种逻辑条件的补丁在未来还有很长的路要走。

    但是,正如您所发现的,子解析器机制可以很好地处理您的特定情况。

    你不需要使用parents机制:

    sp = parser.add_subparsers()
    
    sp_scan = sp.add_parser('scan', help='scans directories')
    sp_scan.add_argument('-a', '--a', help='first num', required=True)
    sp_scan.add_argument('-b', '--b', help='second num', required=True)
    
    sp_save = sp.add_parser('save', parents=[save_parser], help='saves something')
    sp_save.add_argument('-d', '--d', help='directory path', required=True)
    sp_save.add_argument('-n', '--n', help='name of the file', required=True)
    

    parents 机制在这里有效,但更适用于解析器在其他地方定义(并导入)或在多个子解析器中重用的情况。例如,如果您有许多子解析器共享一组核心参数(以及它们自己独特的参数)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-07-29
      • 2017-01-03
      • 2015-07-02
      • 2013-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多