我在Python 2.7中使用argparse
来解析命令行参数。是否有一些预定义的条件解析可以处理以下示例?
-x1
,则必须指定-x2 -x3
,但-x4
是可选的。-x5
,则必须指定-x4
,但-x2
是可选的。如果没有在parser.parse_args()
之后写条件,有没有办法做到这一点?
答案 0 :(得分:3)
是。您可以在最终parser.parse_args(...)
之前编写条件并重新解析:
# ... args = parser.parse_args(arguments)
try:
if args.x1:
# add more conditions
parser.add_argument("-x2", ... )
except NameError:
# x1 not specified
pass
# add the rest
# re-parse arguments
# ... args = parser.parse_args(arguments)
答案 1 :(得分:1)
有一个Python bug问题,要求“必然包容性”#39;以argparse
方式为基础的mutually exclusive groups
组。 http://bugs.python.org/issue11588
提出的主要想法是在退出parse_args
之前应用像你这样的组合规则。此时,已经看到了一个列表(或集合)的参数。设计全面,合理且直观的用户界面的主要挑战。编写反映条件的使用线也很有挑战性。
但是如果没有那个补丁,我担心你会根据你在args命名空间中找到的值编写自己的测试。如果你正确选择默认值,那就不难了。
另一种可能性是使用subparser。您必须将-x1
,-x5
更改为位置选择,x1
和x5
,当然它们将是互斥的。
https://stackoverflow.com/a/27258765/901925 一个简单的测试示例:
if args.option1 is None and args.option2 is None:
parser.error('at least one of option1 and option2 is required')
答案 2 :(得分:0)
这是一个完整的例子
像这样调用它:
./foo.py --first opt2 --second bar3 # bad ./foo.py --first opt2 --second bar1 # ok ./foo.py --first opt1 --second foo1 # ok
hth
#!/usr/bin/env python3
import argparse
FIRST_CHOICES = [ 'opt1', 'opt2' ]
FIRST_CHOICE_DEFAULT = 'opt1'
SECOND_CHOICES = [ 'foo1', 'foo2' ]
SECOND_CHOICE_DEFAULT = 'foo1'
SECOND_ALTERNATIVE_CHOICES = [ 'bar1', 'bar2' ]
SECOND_ALTERNATIVE_CHOICE_DEFAULT = 'bar1'
class ArgsActionFirstChoicesStrings():
def __init__(self):
self.choices = FIRST_CHOICES
def tostring(self):
return ', '.join([repr(action) for action in self.choices])
class ArgsActionFirst(argparse.Action):
def __init__(self, option_strings, dest, nargs=None, **kwargs):
if nargs is not None:
raise ValueError("nargs not allowed")
self.args = ArgsActionFirstChoicesStrings()
super(ArgsActionFirst, self).__init__(option_strings, dest, **kwargs)
def __call__(self, parser, namespace, value, option_string=None):
if value:
if value not in self.args.choices:
message = ("invalid choice: {0!r} (choose from {1})"
.format(value, self.args.tostring()))
raise argparse.ArgumentError(self, message)
setattr(namespace, self.dest, value)
else:
setattr(namespace, self.dest, FIRST_CHOICE_DEFAULT)
class ArgsActionSecondChoicesStrings():
def __init__(self):
self.choices = SECOND_CHOICES
def tostring(self):
return ', '.join([repr(action) for action in self.choices])
class ArgsActionSecond(argparse.Action):
def __init__(self, option_strings, dest, nargs=None, **kwargs):
if nargs is not None:
raise ValueError("nargs not allowed")
self.args = ArgsActionSecondChoicesStrings()
super(ArgsActionSecond, self).__init__(option_strings, dest, **kwargs)
def __call__(self, parser, namespace, value, option_string=None):
if value:
if value not in self.args.choices:
message = ("invalid choice: {0!r} (choose from {1})"
.format(value, self.args.tostring()))
raise argparse.ArgumentError(self, message)
setattr(namespace, self.dest, value)
else:
setattr(namespace, self.dest, FIRST_CHOICE_DEFAULT)
class ArgsActionSecondAlternativeChoicesStrings():
def __init__(self):
self.choices = SECOND_ALTERNATIVE_CHOICES
def tostring(self):
return ', '.join([repr(action) for action in self.choices])
class ArgsActionSecondAlternative(argparse.Action):
def __init__(self, option_strings, dest, nargs=None, **kwargs):
if nargs is not None:
raise ValueError("nargs not allowed")
self.args = ArgsActionSecondAlternativeChoicesStrings()
super(ArgsActionSecondAlternative, self).__init__(option_strings, dest, **kwargs)
def __call__(self, parser, namespace, value, option_string=None):
if value:
if value not in self.args.choices:
message = ("invalid choice: {0!r} (choose from {1})"
.format(value, self.args.tostring()))
raise argparse.ArgumentError(self, message)
setattr(namespace, self.dest, value)
else:
setattr(namespace, self.dest, SECOND_ALTERNATIVE_CHOICE_DEFAULT)
def test_common_parse_arguments():
parser = argparse.ArgumentParser("test")
parser.add_argument('--first',
action=ArgsActionFirst,
default = FIRST_CHOICE_DEFAULT,
metavar='ACTION',
help="Operating system, choose from: " +
ArgsActionFirstChoicesStrings().tostring())
args, unknown = parser.parse_known_args()
try:
if args.first == "opt1":
parser.add_argument('--second',
action=ArgsActionSecond,
default = SECOND_CHOICE_DEFAULT,
metavar='ACTION',
help="SECOND choose from: " +
ArgsActionSecondChoicesStrings().tostring())
parser.parse_args()
elif args.first == "opt2":
parser.add_argument('--second',
action=ArgsActionSecondAlternative,
default = SECOND_ALTERNATIVE_CHOICE_DEFAULT,
metavar='ACTION',
help="SECOND choose from: " +
ArgsActionSecondAlternativeChoicesStrings().tostring())
else:
raise ValueError("unknown os, choices are: " +
ArgsActionFirstChoicesStrings().tostring())
except NameError:
pass
args = parser.parse_args()
print("first option is {}".format(args.first))
print("second option is {}".format(args.second))
return args
if __name__ == "__main__":
test_common_parse_arguments()