【发布时间】:2014-12-30 02:41:40
【问题描述】:
我正在编写一个带有一个必需参数的脚本,然后可以基于此更改以下参数的解释。大多数组合都很顺利,但有一个给我带来了麻烦。它是三个参数的重复组,所有字符串。例如:
$ 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)+
我无法控制输入的格式。不过,可以选择通过标准输入而不是在命令行上接收。使用正则表达式将其作为字符串处理可能更容易,这也允许我通过加入 argv 来处理两者。
还有其他几个 SO 答案,这些地址与 argparse 类似。
hpaulj 在这里有两个有用的回复:Argparse, handle repeatable set of items 在这里:Python argparser repeat subparse
现在几个小时后,我还没有弄清楚如何使用 argparse 进行这项工作,而不需要一些hacky。首先,剥离第一个参数,然后迭代直到剩余的参数消失。我想把它保存在同一个命名空间对象中,就像我能弄清楚如何正确地做到这一点一样。基于上述答案之一的一些演示代码:
#!/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')
【问题讨论】:
-
请问这些论点是从哪里来的?为什么你无法控制它们?
-
我无法更改的上游应用程序。
-
我不认为 argparse 是要走的路......我只是不确定你的情况是什么。 Argparse 旨在解析参数(令人惊讶)。虽然它可以工作,但它听起来不像是工作的工具。如果您可以使用数据作为参数调用 python 脚本,也许您可以使用消息传递系统以某种方式将参数直接流式传输到脚本?
-
是的,它从简单的 arg 处理开始。并且适用于其他十几种情况。但这似乎在推动 argparse 的意图。我认为采用标准输入或将 argv 转换为字符串并使用正则表达式可能是更清洁但破坏性最小的解决方案。我还是会等着看有没有人有建议。
-
什么在调用脚本?