(问题的简化形式。)我正在编写一个涉及一些 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
功能,如果你忘记了我们想要前缀(以便能够添加多个相同类型的解析器)
可能还有命名空间(这样我们就可以构建树状结构的命名空间来反射(reflect)组件的结构)。
当然,我们希望 larger_component 和 larger_parser 能够以相同的方式组合,并且传递给某个组件的命名空间对象应该始终具有相同的内部形状/命名结构。
问题似乎是 argparse
API 基本上是关于改变你的解析器,但查询它们更困难 - 如果你转
数据类型直接进入解析器,你可以只遍历这些对象。如果用户编写了一堆函数来手动向解析器添加参数,我设法破解了一些有用的东西,但是每个 add_argument
调用都必须带有前缀,并且整个事情变得非常难以理解并且可能不可组合。 (您可以以复制内部数据结构的某些部分为代价对此进行抽象......)。我还尝试将 parser
和 group
对象子类化......
你可以想象这可能使用更代数的 CLI 解析 API 是可能的,但我认为重写 argparse
不是一个好的解决方案。
是否有已知/直接的方法来做到这一点?
最佳答案
一些可以帮助您构建更大的解析器的想法:
parser = argparse.ArgumentParser(...)
arg1 = parser.add_argument('--foo',...)
现在 arg1
是对 add_argument
创建的 Action
对象的引用。我建议在交互式 shell 中执行此操作并查看其属性。或者至少打印它的 repr
。您还可以尝试修改属性。
解析器“了解”参数的大部分信息都包含在这些操作
中。从某种意义上说,解析器是一个“包含”一堆“ Action ”的对象。
另请参阅:
parser._actions
这是解析器的主要操作列表,其中将包括默认帮助以及您添加的帮助。
parents
机制将Action
引用从父级复制到子级。请注意,它不会复制 Action 对象。它还会重新创建参数组 - 但这些组仅用于对帮助热线进行分组。它们与解析无关。
args1, extras = parser.parse_known_args(argv, namespace)
在处理多个解析器时非常有用。有了它,每个解析器都可以处理它知道的参数,并将其余的传递给其他人。尝试理解该方法的输入和输出。
我们在前面的 SO 问题中讨论了复合 Namespace
对象。默认的 argparse.Namespace
类是一个带有 repr
方法的简单对象类。解析器仅使用 hasattr
、getattr
和 setattr
,尽量做到非特定。您可以构造一个更详细的命名空间类。
argparse subcommands with nested namespaces
您还可以自定义Action
类。这是大多数值插入命名空间的地方(尽管在其他地方设置了默认值)。
IPython
使用 argparse
,既用于主调用,也用于内部的 magic
命令。它从 config
文件构造许多参数。因此,可以使用默认配置、自定义配置或在最后一刻通过命令行参数设置许多值。
关于python - 使用 Python/argparse 创建可组合/分层命令行解析器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33224213/