【问题标题】:ArgumentParser with optional argument (in a mutually_exclusive_group)带有可选参数的 ArgumentParser(在互斥组中)
【发布时间】:2014-01-18 08:19:20
【问题描述】:

我正在尝试做一件非常简单的事情 - 只有两个选项:-p-c,相互排斥,可能有也可能没有参数,请使用 th...is可选参数或不使用th...at。这就是我得到的:

def main():

    import argparse
    parser = argparse.ArgumentParser(description = '''ArgParser with optional argument''',
                                     argument_default = argparse.SUPPRESS)

    group1 = parser.add_mutually_exclusive_group(required=True)

    group1.add_argument('-p', '--project', dest='proj',
                        nargs='?', const='all', type=str,
                        help='list of project(s)')
    group1.add_argument('-c', '--component', dest='comp',
                        nargs='?', const='all', type=str,
                        help='list of Component(s)')

    args = parser.parse_args()
    print(args)

    if args.proj:
        outString = 'project/'+args.proj if args.proj is not 'all' else 'projects'
    elif args.comp:
        outString = 'component/'+args.comp if args.comp is not 'all' else 'components'
    else: pass

    print('OutPutString: '+outString)

if __name__ == "__main__":

    import sys
    try: sys.exit(main())
    except KeyboardInterrupt: pass
    finally: print

对于if-elif-else 块中的第一个条件,它工作得很好,所以它工作:

dass@mon105:~$ ./argParseOpts.py -p 
Namespace(proj='all')
OutPutString: projects
#
dass@mon105:~$ ./argParseOpts.py -p testing
Namespace(proj='testing')
OutPutString: project/testing

但如果使用-c 而不是-p(即第二个条件)则不是:

dass@mon105:~$ ./argParseOpts.py -c 
Namespace(comp='all')

Traceback (most recent call last):
  File "./argParseOpts.py", line 32, in <module>
    try: sys.exit(main())
  File "./argParseOpts.py", line 21, in main
    if args.proj:
AttributeError: 'Namespace' object has no attribute 'proj'

谁能告诉我我是否遗漏了什么或做错了什么?使用 v2.7.2,如果这很重要。干杯!!

【问题讨论】:

  • @MartijnPieters:嗯......我在 v2.7.3 上也看到了同样的错误。试图找出我是否在任何地方安装了 v2.7.5。但是在量产机上,我还是得用v2.7.2。
  • 抱歉,当我在为您的问题测试修复程序的过程中走开,然后忘记我把它放进去时,这就是您得到的结果。:-P
  • @MartijnPieters:刚刚在原始帖子中添加了if __name__ == "__main__": 位,以确保不会导致此问题。在 v3.3.3 上测试过的 Juts 仍然是同样的错误。但是找不到安装了 v2.7.5 的盒子。

标签: python python-2.7 arguments argparse


【解决方案1】:

没有设置属性,因为您将argument_default 值设置为argparse.SUPPRESS,这意味着除非属性具有显式值,否则永远不会设置属性。

Set 可以为每个参数设置一个显式的default=None 值,以再次获得这些特定选项的属性:

group1.add_argument('-p', '--project', dest='proj',
                    nargs='?', const='all', type=str,
                    help='list of project(s)', default=None)
group1.add_argument('-c', '--component', dest='comp',
                    nargs='?', const='all', type=str,
                    help='list of Component(s)', default=None)

args.projargs.comp 属性将再次被设置。 None 是一个 false 值,因此 if args.proj 测试不会通过移动到另一个分支,例如。

另一种方法是使用hasattr()查看是否设置了属性:

if hasattr(args, 'proj'):

【讨论】:

  • 我认为,原来的问题仍然是一样的——它适用于第一个条件。通过您的修复,如果我切换 if-elif 块,-p 再次失败。
  • @MacUsers:所以也为其他选项添加default=None
  • hasattr() 是我的方式。 default=None 实际上是将它们都添加到命名空间中,这可能会在我的原始脚本中带来一些其他问题。感谢那。干杯!!
  • 您的每个参数 default 正在覆盖解析器的 SUPPRESS 默认值。
  • @hpaulj:确实;在我的回答中更明确地说明了这一点。
【解决方案2】:

由于已经使用 Argparse 解决了这个问题,我建议使用 docopt 作为替代方案。以标准格式编写界面帮助消息,这就是您需要做的一切。如果我正确理解你的用法,它会是这样的。

在这种情况下解决问题的关键是制作-p-c 标志并为字符串使用不同的变量NAME

"""Usage:
    myprog (-p [NAME] | -c [NAME])

Options:
    -p, --project        list of project(s)
    -c, --component      list of component(s)
"""
from docopt import docopt

if __name__ == "__main__":
    arguments = docopt(__doc__)
    print(arguments)

    name = 'all' if arguments['NAME'] is None else arguments['NAME']
    if arguments['--project']:
        ...
    elif arguments['--component']:
        ...

如果我们只打印参数,使用模式将如下所示。

$ python myprog.py
Usage:
...

$ python myprog.py -p
{'--project': True,
 '--component': False,
 'NAME': None}

$ python myprog.py -c foo
{'--project': False,
 '--component': True,
 'NAME': 'foo'}

$ python myprog.py -p foo -c bar
Usage:
...

【讨论】:

    【解决方案3】:

    错误的原因是SUPPRESS

    parser = argparse.ArgumentParser(description = '''ArgParser with optional argument''',
                                     argument_default = argparse.SUPPRESS)
    

    使用此选项,如果参数未出现在 argv 中,则它不会出现在 Namespace 中。

    dass@mon105:~$ ./argParseOpts.py -c 
    Namespace(comp='all')
    
    Traceback (most recent call last):
      File "./argParseOpts.py", line 32, in <module>
        try: sys.exit(main())
      File "./argParseOpts.py", line 21, in main
        if args.proj:
    AttributeError: 'Namespace' object has no attribute 'proj'
    

    当你给它-p 时,args.comp 会返回同样的错误(除非你先检查了proj)。

    我喜欢在交互式 shell 中测试此类问题(例如 IPython)。在那里我可以输入你的parser 定义,然后发出如下命令:

    In [35]: parser.parse_args(['-p'])
    Out[35]: Namespace(proj='all')
    
    In [36]: parser.parse_args(['-c'])
    Out[36]: Namespace(comp='all')
    
    In [37]: parser.parse_args(['-c','test'])
    Out[37]: Namespace(comp='test')
    

    很明显只设置了一个属性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-10-27
      • 1970-01-01
      • 2015-04-20
      • 2017-01-17
      • 1970-01-01
      • 1970-01-01
      • 2019-02-16
      • 1970-01-01
      相关资源
      最近更新 更多