【发布时间】:2016-01-18 09:04:54
【问题描述】:
(问题的简化形式。)我正在编写一个涉及一些 Python 组件的 API。这些可能是函数,但具体来说,我们假设它们是对象。我希望能够从命令行解析各种组件的选项。
from argparse import ArgumentParser
class Foo(object):
def __init__(self, foo_options):
"""do stuff with options"""
"""..."""
class Bar(object):
def __init__(sef, bar_options):
"""..."""
def foo_parser():
"""(could also be a Foo method)"""
p = ArgumentParser()
p.add_argument('--option1')
#...
return p
def bar_parser(): "..."
但现在我希望能够构建更大的组件:
def larger_component(options):
f1 = Foo(options.foo1)
f2 = Foo(options.foo2)
b = Bar(options.bar)
# ... do stuff with these pieces
很好。但是如何编写合适的解析器呢?我们可能希望这样:
def larger_parser(): # probably need to take some prefix/ns arguments
# general options to be overridden by p1, p2
# (this could be done automagically or by hand in `larger_component`):
p = foo_parser(prefix=None, namespace='foo')
p1 = foo_parser(prefix='first-foo-', namespace='foo1')
p2 = foo_parser(prefix='second-foo-', namespace='foo2')
b = bar_parser()
# (you wouldn't actually specify the prefix/namespace twice: )
return combine_parsers([(p1, namespace='foo1', prefix='first-foo-'),
(p2,...),p,b])
larger_component(larger_parser().parse_args())
# CLI should accept --foo1-option1, --foo2-option1, --option1 (*)
如果你忘记我们想要前缀的话,它看起来有点像argparse 的parents 功能(以便能够添加多个相同类型的解析器)
可能还有命名空间(这样我们就可以构建树结构的命名空间来反映组件的结构)。
当然,我们希望 large_component 和 large_parser 以相同的方式可组合,并且传递给某个组件的命名空间对象应该始终具有相同的内部形状/命名结构。
问题似乎在于argparse API 基本上是关于改变你的解析器,但查询它们更困难 - 如果你转过
直接将数据类型导入解析器,您可以只遍历这些对象。如果用户编写一堆函数来手动向解析器添加参数,我设法破解了一些有些工作的东西,但是每个add_argument 调用都必须带一个前缀,整个事情变得非常难以理解并且可能不可组合。 (您可以以复制内部数据结构的某些部分为代价对其进行抽象......)。我还尝试继承 parser 和 group 对象...
您可以想象这可能使用更代数的 CLI 解析 API 来实现,但我不认为重写 argparse 在这里是一个好的解决方案。
是否有已知/直接的方法可以做到这一点?
【问题讨论】:
-
您能展示一个您想使用的命令行示例吗?乍一看,您似乎想要
subparsers(argparse 默认提供),但我不能 100% 确定这是否适合您的需求。 -
subparsers似乎是解析器的“总和”(解析器 A、B 或 ...),而我想要一个“产品”(所有选项同时可用)。 -
例如,请参阅我在问题中用
(*)表示的行。
标签: python command-line-arguments argparse composition