【问题标题】:python, argparse: enable input parameter when another one has been specifiedpython,argparse:在指定另一个输入参数时启用输入参数
【发布时间】:2012-07-12 09:40:20
【问题描述】:

在我的 python 脚本中,我希望能够在指定另一个可选参数时使用可选输入参数。示例:

$ python myScript.py --parameter1 value1
$ python myScript.py --parameter1 value1 --parameter2 value2

但不是:

$ python myScript.py --parameter2 value2

如何使用 argparse 执行此操作?

谢谢!

【问题讨论】:

  • 如果myScript.py --parameter2 value2 --parameter1 value1,你想发生什么?如果您希望它通过,这是一个非常难以处理的案例。
  • bugs.python.org/issue11588 是对mutually_inclusive_group 功能的错误请求。这在这种情况下不太适用,因为--parameter1 可能在没有--parameter2 的情况下发生。如果您对如何实施此限制或相关限制有任何想法,请为该问题做出贡献。

标签: python parameters arguments argparse


【解决方案1】:

在将--parameter2 添加到解析器之前,您可以使用parse_known_args() 检查是否给出了--parameter1

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--parameter1', dest='p1')
args = parser.parse_known_args()[0]
if args.p1:
  parser.add_argument('--parameter2', dest='p2')
args = parser.parse_args()

if args.p1:
  print args.p1
if args.p2:
  print args.p2

结果:

$ python myScript.py --parameter1 a
a
$ python myScript.py --parameter1 a --parameter2 b
a
b
$ python myScript.py --parameter2 b
usage: myScript.py [-h] [--parameter1 P1]
myScript.py: error: unrecognized arguments: --parameter2 b

【讨论】:

  • --help 会不准确。
【解决方案2】:

使用自定义操作:

import argparse

foo_default=None    

class BarAction(argparse.Action):
    def __call__(self,parser,namespace,values,option_string=None):
        didfoo=getattr(namespace,'foo',foo_default)
        if(didfoo == foo_default):
            parser.error( "foo before bar!")
        else:
            setattr(namespace,self.dest,values)

parser=argparse.ArgumentParser()
parser.add_argument('--foo',default=foo_default)
parser.add_argument('--bar',action=BarAction,help="Only use this if --foo is set")

#testing.
print parser.parse_args('--foo baz'.split())
print parser.parse_args('--foo baz --bar cat'.split())
print parser.parse_args('--bar dog'.split())

如果您可以依赖 argparse 的一些未记录的行为,这甚至可以以更易于维护的方式完成:

import argparse

parser=argparse.ArgumentParser()
first_action=parser.add_argument('--foo',dest='cat',default=None)

class BarAction(argparse.Action):
    def __call__(self,parser,namespace,values,option_string=None):
        didfoo=getattr(namespace,first_action.dest,first_action.default)
        if(didfoo == first_action.default):
            parser.error( "foo before bar!")
        else:
            setattr(namespace,self.dest,values)

parser.add_argument('--bar',action=BarAction,
                    help="Only use this if --foo is set")

#testing.
print parser.parse_args('--foo baz'.split())
print parser.parse_args('--foo baz --bar cat'.split())
print parser.parse_args('--bar dog'.split())

在这个例子中,我们得到foo 的默认值,它的目的地来自add_argument 返回的操作对象(我找不到任何地方都记录了add_argument 的返回值)。这仍然有点脆弱(例如,如果您想为 --foo 参数指定 type= 关键字)。

最后,你可以在解析之前检查sys.argv

import sys
if ("--parameter2" in sys.argv) and ("--parameter1" not in sys.argv):
    parser.error("parameter1 must be given if parameter2 is given")

如果--parameter1 也可以由--p1 触发,这将变得更加棘手,但你明白了。然后你可以使用

if (set(sys.argv).intersection(('--p2',...)) and 
    not set(sys.argv).intersection(('--p1',...)))

这里的优点是它不需要任何特定的顺序。 (--p2 不需要在命令行上跟随 --p1)。而且,和以前一样,您可以通过parser.add_argument(...) 返回的option_strings 属性获取将触发您的特定操作的命令字符串列表。例如

import argparse
import sys   
parser=argparse.ArgumentParser()
action1=parser.add_argument('--foo')
action2=parser.add_argument('--bar',
                            help="Only use this if --foo is set")

argv=set(sys.argv)
if (( argv & set(action2.option_strings) ) and 
      not ( argv & set(action1.option_strings) )):
                #^ set intersection
     parser.error(' or '.join(action1.option_strings)+
                  ' must be given with '+
                  ' or '.join(action2.option_strings))

【讨论】:

    【解决方案3】:

    一个想法是手动检查调用parser.parse_args() 的输出,并在使用--parameter2 但未使用--parameter1 时引发异常或以其他方式失败。

    您也可以尝试将custom action(向下滚动一点)设置为--parameter2,检查--parameter1 是否存在于命名空间中。

    最后,您可以尝试使用subparsers,虽然我不知道它是否会让您为--parameter1 指定一个值。

    【讨论】:

      猜你喜欢
      • 2014-10-17
      • 2020-05-08
      • 2013-03-30
      • 2013-11-26
      • 2021-06-15
      • 2013-03-30
      • 2020-09-17
      • 2018-11-25
      • 2016-10-16
      相关资源
      最近更新 更多