【问题标题】:Using python argparse on repeating groups在重复组上使用 python argparse
【发布时间】: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 转换为字符串并使用正则表达式可能是更清洁但破坏性最小的解决方案。我还是会等着看有没有人有建议。
  • 什么在调用脚本?

标签: python argparse


【解决方案1】:

这是一个可以简化重复部分的粗略序列:

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 一样。

【讨论】:

  • 谢谢!将命名空间传回是我昨晚发布后想出的。您刚刚确认它可能是除了完整重构之外的最佳选择。它足够干净。能够根据需要使用不同的解析器迭代输入,但在同一个命名空间中工作实际上是一种非常酷的方法。只需要小心不要意外破坏任何东西。我会将我更新的代码放在问题中作为其他人的参考。再次感谢!
猜你喜欢
  • 2021-10-08
  • 2017-07-23
  • 2013-10-07
  • 2015-05-20
  • 2016-12-27
  • 2020-08-08
  • 2020-06-19
  • 2021-12-20
相关资源
最近更新 更多