argparse 仅在位置参数之前解析
Posted
技术标签:
【中文标题】argparse 仅在位置参数之前解析【英文标题】:Argparse parse only before positional argument 【发布时间】:2018-12-22 12:08:27 【问题描述】:如何让 argparse 只解析位置参数之后的命令?
如果我有命令 pythonfile.py -d dir -e test pos_cmd_1 -d
我怎样才能让第一个 -d
由 argparse 解析,而位置命令之后的任何内容都由该命令本身解析(基本上将 pos_cmd_1 -d
作为单个参数读取)
所以参数列表将是
pythonfile.py -d 目录 -e 测试 pos_cmd_1 -d -s -etc因此,位置命令之前的任何内容都是可选的。位置命令之后的任何内容都将成为位置命令本身的一部分。
编辑:当尝试使用双破折号运行命令时,它告诉我后面的参数无法识别。
pythonfile.py -d testdir -e test -- command -d -s
它说-d -s
是无法识别的参数,而不是将它们与命令捆绑在一起。
【问题讨论】:
用双破折号结束开关怎么样?pythonfile.py -d dir -e test -- pos_cmd_1 -d
至少很清楚选项在哪里停止
您能否提供一些背景信息:您认为您为什么要这样做?
@jonrsharpe 为 docker-compose 编写一个包装器,让我可以添加自定义可扩展性,并且一些参数标志与 docker 命令的参数标志重叠。因此,如果 -d
在 compose 命令(up/start/kill/etc)之前,则将其解析为我的命令,但如果在之后,它将成为 docker 命令的一部分。所以python.py -d test up -d
,其中第二个-d
将由docker 解析。
在这种情况下使用--
,它经常出现在“...然后将这些参数传递给任何那个调用”。
在我看来,应该从 shell 正确调用该实用程序(即根据其记录的用法)。为此目的使用引号或双破折号。这些都是众所周知的标准,应该遵守。示例:pythonfile.py -d dir -e test "pos_cmd_1 -d"
【参考方案1】:
你可以通过稍微改变你的命令行来实现这一点
pythonfile.py -d dir -e test -- pos_cmd_1 -d
通过添加--
,您告诉 argparse 停止寻找选项。所以所有剩余的参数都设置在位置参数列表中。
另一种方法是引用其余参数:
pythonfile.py -d dir -e test "pos_cmd_1 -d"
并且(因为它只创建一个位置参数)在拆分后的字符串上再次使用参数解析器(如果您想在这些参数中传递带引号的字符串,则不理想)
这些方法的优点是它们受到argparse
、getopt
的原生支持,而且这是一种标准机制,不会让您的命令的用户感到惊讶。
如果你想坚持你的方法,也许你可以预处理参数列表,通过连续检测 2 个非选项参数来插入双破折号:
args = "-d dir -e test pos_cmd_1 -d".split()
oldarg=""
for i,a in enumerate(args):
if oldarg and oldarg[0]!='-' and a[0]!='-':
args.insert(i,'--')
break
oldarg = a
args
现在是:['-d', 'dir', '-e', 'test', '--', 'pos_cmd_1', '-d']
【讨论】:
这两种方法都有效,但是否没有选项可以让我在无需用户自己输入 -- 的情况下执行此操作?我唯一的选择是在位置命令之后预解析字符串以获取所有内容吗?位置命令可能有很多东西,所以我只需要通过将 arg 列表中的每个项目与可能的命令进行比较,将它和它之后的所有内容放入自己的字符串中吗?【参考方案2】:使用简单的解析器:
In [2]: p = argparse.ArgumentParser()
In [3]: p.add_argument('-d');
In [4]: p.add_argument('-e');
In [5]: p.parse_args('-d dir -e test pos_cmd_1 -d'.split())
usage: ipython3 [-h] [-d D] [-e E]
ipython3: error: argument -d: expected one argument
它尝试解析最后一个'-d'并遇到错误。 parse_known_args
没有帮助。
使用 '-d' 和 '-e' 以外的字符串 parse_known_args
有效:
In [7]: p.parse_known_args('-d dir -e test pos_cmd_1 -s'.split())
Out[7]: (Namespace(d='dir', e='test'), ['pos_cmd_1', '-s'])
带有REMAINDER
nargs 的位置似乎可以工作:
In [8]: a1 = p.add_argument('rest', nargs='...') # argparse.REMAINDER
In [9]: p.parse_args('-d dir -e test pos_cmd_1 -s'.split())
Out[9]: Namespace(d='dir', e='test', rest=['pos_cmd_1', '-s'])
In [10]: p.parse_args('-d dir -e test pos_cmd_1 -d'.split())
Out[10]: Namespace(d='dir', e='test', rest=['pos_cmd_1', '-d'])
REMAINDER
应该像“--”一样工作,捕获输入以供其他解析器或命令使用。
如果预计会捕获整个命令行,则可能会出现问题,如下所示:
In [12]: p.parse_args('-s pos_cmd_1 -d'.split())
usage: ipython3 [-h] [-d D] [-e E] ...
ipython3: error: unrecognized arguments: -s
https://docs.python.org/3/library/argparse.html#nargs
【讨论】:
以上是关于argparse 仅在位置参数之前解析的主要内容,如果未能解决你的问题,请参考以下文章