【问题标题】:How do I get back the option string using argparse?如何使用 argparse 取回选项字符串?
【发布时间】:2015-06-07 04:02:08
【问题描述】:
parser = argparse.ArgumentParser()
parser.add_argument("-p", "--pattern", help="Pattern file")
args = parser.parse_args()

现在可以从args 取回字符串"--pattern" 吗? 我需要这个字符串,这样我就可以构造一个 cmd 列表来像Popen(['some_other_program', args.pattern.option_string, args.pattern], ...) 一样传递给 Popen,而无需重复它(并且必须在两个地方维护它)(Popen(['some_other_prog', '--pattern', args.pattern], ...))。

我需要为另一个程序创建一个包装器。一些 args 需要传递给被包装的程序(通过 Popen),一些是包装器需要的。


有没有比下面的例子更好的方法?

pass_1 = '--to-be-passed'
parser = argparse.ArgumentParser()
parser.add_argument("-p", pass_1, help="Pass me on")
parser.add_argument("-k", "--arg-for-wrapper")
args = parser.parse_args()

...
process = Popen(['wrapped_program', pass_1, args.pass_1], ...)
... 

这种将args保存在变量中的方法不是很好:

  1. 同时持有空头期权和多头期权变得很困难。
  2. Popen 如果在另一个函数中调用需要将这些变量(或它们的字典)传递给函数。这似乎是多余的,因为传递给它的 args 应该就足够了。

【问题讨论】:

  • 你为什么不把它存储在一个变量中呢? pattern_str = '--pattern',然后是 ..add_argument(... pattern_str ...)。那里 - 只有一个维护点。
  • 听起来你正试图硬编码两个独立程序之间的依赖关系(而且不灵活:“这些程序必须共享选项名称”)。这真的是你想做的吗?
  • @Hurkyl 是的,python 程序是另一个程序的包装器。
  • 同意@AmiTavory 的解决方案是唯一可以按照您尝试的方式进行维护的解决方案。也许一个全局字典将所有模式作为键,将它们的选项标志作为值,以及大量评论说明为什么将它们拉入全局
  • @AmiTavory argparser 解析两种类型的 args - 那些特定于 python 包装器的和那些要传递给 Popen 的。拥有变量(用于将 args 传递给 Popen)而不是那些特定于包装器的变量似乎有点混乱,尽管这是一个更好的选择。我只是问有没有更好的方法。

标签: python popen argparse


【解决方案1】:

在您的add_argument 通话中添加dest。

parser.add_argmument("p", "--pattern", dest="pattern", help="your help text")
args = parser.parse_args()
args = vars(args)

您可以使用 args["pattern"] 引用该模式。

【讨论】:

  • argparse 从--pattern 推导出dest 是pattern。所以添加的“dest”不是必需的。 args 是命名空间对象,而不是字典。 vars(args) 从中生成字典。
  • 这不能回答问题。他在问他如何才能拥有,例如,--some-opt 只在一个地方定义,但您没有说明如何从解析器中取出字符串 --some-opt。
【解决方案2】:

似乎没有一种简单的方法可以从parser.parse_args() 的结果中获取原始选项字符串,但您可以从parser 对象中获取它们。您只需要查看其__dict__,以便在创建后检索parser 设置。在您的情况下,您需要 _option_string_actions 字段。不幸的是,这似乎没有得到官方支持,因为我找不到专门用于此的 ArgumentParser 方法,所以 YMMV。在 Python 3 上:

演示:

parser = argparse.ArgumentParser()
parser.add_argument('--foo', '-f', type=int, default=1000, help='intensity of bar')
parser.add_argument('--bar', '-b', type=str, default='bla', help='whatever')
store_action_dict=vars(parser)['_option_string_actions']
print(store_action_dict.keys())    # dict_keys(['--help', '-b', '-f', '-h', '--foo', '--bar'])

【讨论】:

  • 带有前导下划线的变量据说没有暴露。所以_option_string_actions 是私有变量,可以随时更改。所以我个人会避免这种类型的编码
【解决方案3】:

已删除的答案和 cmets 表明您对您想要的内容有些困惑。所以我会增加这种混乱。

解析器通常不会记录选项字符串。但是它提供给Action__call__ 方法。所以自定义 Action 类可以保存它。 argparse 文档中的 FooAction 自定义类示例说明了这一点。

如果我定义了这个动作子类:

In [324]: class PassThru(argparse._StoreAction):
def __call__(self, parser, namespace, values, option_string=None):
    setattr(namespace, self.dest, [values, option_string])

In [324]: p.add_argument('-o','--other',action=PassThru)

选项字符串与值一起记录('-o'或'--other'):

In [322]: p.parse_args('-p test -o teseting'.split())
Out[322]: Namespace(other=['teseting', '-o'], pass_me_on='test')

In [323]: p.parse_args('-p test --other teseting'.split())
Out[323]: Namespace(other=['teseting', '--other'], pass_me_on='test')

显然 option_string 和 value 可以以不同的顺序记录在字典中,作为命名空间中的单独属性等。


还有其他方法可以将选项传递给另一个程序,特别是在包装解析器不需要自己处理它们的情况下。

argparse 从sys.argv[1:] 获取参数,并且不更改它。因此,即使您的解析器使用了一些参数,您也可以将该列表传递给 popen(全部或部分)。

argparse 文档在nargs=REMAINDER 下有一个示例,它为自己解析一些参数,然后收集其余参数以传递给另一个程序。这是他们的例子:

>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('--foo')
>>> parser.add_argument('command')
>>> parser.add_argument('args', nargs=argparse.REMAINDER)
>>> print(parser.parse_args('--foo B cmd --arg1 XX ZZ'.split()))
Namespace(args=['--arg1', 'XX', 'ZZ'], command='cmd', foo='B')

所以你可以打电话给popen 类似

plist = ['wrapped_program']
plist.extend(args.args)
popen(plist, ...)

使用parse.parse_known_args 也可用于将未解析的单词收集到“附加”列表中。文档的那部分讨论了将这些字符串传递给另一个程序(就像你正在做的那样)。与 REMAINDER 情况相比,多余的东西不必放在最后。

当然,只有当这个解析器本身不需要--pattern 时,这些才有效。如果它解析它,那么它不会出现在 REMAINDER 或 extras 中。在这种情况下,您必须将其添加回您提供的列表中 popen

我会调整你的解析器:

pass_1 = 'passed'  # without the -- or internal -
dpass_` = '--'+pass_
parser = argparse.ArgumentParser()
parser.add_argument("-p", dpass_1, help="Pass me on")
parser.add_argument("-k", "--arg-for-wrapper")
args = parser.parse_args()
process = Popen(['wrapped_program', dpass_1, getattr(args, pass_1)], ...)

另一种选择:

parser = argparse.ArgumentParser()
pass_action = parser.add_argument("-p", '--pass-me-on', help="Pass me on")
parser.add_argument("-k", "--arg-for-wrapper")
args = parser.parse_args()

如果你打印 pass_action(在 shell 中)你会得到类似的东西:

 _StoreAction(option_strings=['-p', '--pass-me-on'], dest='pass_me_on', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)

因此您可以从该对象中提取--name 和dest,因此:

process = Popen(['wrapped_program', pass_action.option_strings[-1], getattr(args, pass_action.dest), ...], ...)

您必须查看 sys.argv 以查看使用了哪个 option_string(长、短或其他)。解析器不会在任何地方记录。

注意“--pass-me-on”产生了dest='pass_me_on'。 - 到 _ 的转换可能会使从另一个字符串派生一个字符串变得复杂。

如果您有一个dest 字符串,则必须使用getattr 将其从args 命名空间中拉出,或者使用vars(args)[dest](字典访问)。

另一个问题。如果--patten 有nargs='+', its value will be a list, as opposed to a string. You'd have to careful when merging that into thepopen` 参数列表。

【讨论】:

    猜你喜欢
    • 2014-09-17
    • 1970-01-01
    • 2021-07-25
    • 2022-10-15
    • 2013-12-03
    • 2013-09-21
    • 1970-01-01
    • 2016-03-12
    • 1970-01-01
    相关资源
    最近更新 更多