python,argparse:在指定另一个输入参数时启用输入参数

2022-01-21 00:00:00 python argparse arguments parameters

问题描述

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

In my python script, I want to be able to use an optional input parameter only when another optional parameter has been specified. Example:

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

但不是:

$ python myScript.py --parameter2 value2

如何使用 argparse 执行此操作?

How do I do this with argparse?

谢谢!


解决方案

使用自定义操作:

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 的一些未记录的行为,这甚至可以以更易于维护的方式完成:

This can even be done in a little easier to maintain way if you're OK with relying on some undocumented behavior of 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= 关键字).

In this example, we get the default for foo and it's destination from the action object returned by add_argument (add_argument's return value isn't documented anywhere that I can find). This is still a little fragile (If you want to specify a type= keyword to the --foo argument for example).

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

Finally, you can check sys.argv before parsing.

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 触发,这将变得有点棘手,但你明白了.然后你可以使用

This gets a little more tricky if --parameter1 could also be triggered by --p1, but you get the idea. Then you could use

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

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

The advantage here is that it doesn't require any particular order. (--p2 doesn't need to follow --p1 on the commandline). And, as before, you can get the list of command strings that will trigger your particular action via the option_strings attribute returned by parser.add_argument(...). e.g.

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))

相关文章