我正在编写一个带有一个必需参数的脚本,然后可以根据它更改以下参数的解释。大多数组合进展顺利,但有一个给我带来麻烦。它是一个由三个参数组成的重复组,所有字符串。例如:
$ python script.py p1 p2_1 p2_2 p2_3 p3_1 p3_2 p3_3
或伪正则表达式:
$ python script.py p1 (px_1 px_2 px_3)+
我无法控制输入的格式。可以选择通过stdin接收此命令而不是命令行。使用正则表达式将字符串作为字符串处理可能更容易,这也允许我通过加入argv来处理它们。
还有其他一些SO答案可以解决与argparse类似的问题。
hpaulj在这里有两个有用的回复:Argparse, handle repeatable set of items 在这里:Python argparser repeat subparse
现在几个小时后,我还没弄明白如何在没有hackery的情况下使用argparse来完成这项工作。首先,剥离第一个参数,然后迭代直到剩下的参数消失。我想将它保存在同一个命名空间对象中,就像我可以弄清楚如何正确地执行此操作一样。一些演示代码基于以上答案之一:
#!/usr/bin/env python
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('param1', type=str)
param1, remaining = parser.parse_known_args()
parser = argparse.ArgumentParser()
parser.add_argument('first', type=str, action='append')
parser.add_argument('second', type=str, action='append')
parser.add_argument('third', type=str, action='append')
repeating_args, remaining = parser.parse_known_args(remaining)
while remaining:
another_set, remaining = parser.parse_known_args(remaining)
repeating_args.first.append(another_set.first[0])
repeating_args.second.append(another_set.second[0])
repeating_args.third.append(another_set.third[0])
但这对我来说感觉很糟糕,它迫使我以影响其他参数组合的方式修改代码。使用argparse有更好的方法吗?或者,如果我对此不满意,我应该不使用argparse吗?不幸的是,这意味着我要重写我的很多代码......
感谢。
更新后的代码:
根据hpaulj的答案,这是我正在使用的代码的压缩和工作版本。它比上面的代码要好得多,因为它在解析器配置方面相对通用。我希望它有所帮助。
#!/usr/bin/env python
import sys
import argparse
def parse_args():
# Create the first parser object and get just the first parameter
parser = argparse.ArgumentParser('Argument format parser')
parser.add_argument('arg_format', type=str, help='The first argument.' +
'It tells us what input to expect next.')
args_ns, remaining = parser.parse_known_args()
# Generate a new parser based on the first parameter
parser = formatSpecificParser(args_ns.arg_format)
# There will always be at least one set of input (in this case at least)
args_ns, remaining = parser.parse_known_args(args=remaining, namespace=args_ns)
# Iterate over the remaining input, if any, adding to the namespace
while remaining:
args_ns, remaining = parser.parse_known_args(args=remaining,
namespace=args_ns)
return args_ns
def formatSpecificParser(arg_format):
parser = argparse.ArgumentParser("Command line parser for %s" % arg_format)
if (arg_format == "format_1"):
addArgsFormat1(parser)
# elif (...):
# other format function calls
return parser
def addArgsFormat1(parser):
parser.add_argument('arg1', type=str, action='append', help='helpful text')
parser.add_argument('arg2', type=str, action='append', help='helpful text')
parser.add_argument('arg3', type=str, action='append', help='helpful text')
def main(argv):
args = parse_args()
print (args)
if __name__ == "__main__":
main(sys.argv[1:])
命令行输出:
$ ./example.py format_1 foo bar baz meh meh meh e pluribus unum
Namespace(arg1=['foo', 'meh', 'e'], arg2=['bar', 'meh', 'pluribus'], arg3=['baz', 'meh', 'unum'], arg_format='format_1')
答案 0 :(得分:0)
这是一个粗略的序列,可以简化重复的部分:
In [10]: p=argparse.ArgumentParser()
In [11]: p.add_argument('p2',nargs=3,action='append')
In [12]: ns,rest=p.parse_known_args('p21 p22 p23 p31 p32 p33'.split())
In [13]: ns
Out[13]: Namespace(p2=[['p21', 'p22', 'p23']])
In [14]: rest
Out[14]: ['p31', 'p32', 'p33']
In [15]: ns,rest=p.parse_known_args(rest,ns) # repeat as needed
In [16]: ns
Out[16]: Namespace(p2=[['p21', 'p22', 'p23'], ['p31', 'p32', 'p33']])
正常情况下,'追加'对位置有意义,因为它们不能重复。但是在这里它可以方便地生成一个子列表列表。将较早的命名空间传递到下一个解析步骤可以构建已经解析过的值。这应该与你的3个位置参数同样适用nargs=3
。