python - 解析互斥的可选参数和位置参数,后跟传递参数
问题描述
我正在尝试模拟 Python 解释器命令行行为,如帮助文本所示:
command [options] [-m mod | file] [arg] ...
那是:
- 任意数量的任意选项(其形式
-[a-zA-Z]
可用作标志或带有单个参数) - 之一:
- -m 模组
- 文件
- 零个或多个应按原样可用的参数
我曾尝试使用内置的 argparse 模块,但没有成功。
import argparse
parser = argparse.ArgumentParser()
selector = parser.add_mutually_exclusive_group(required=True)
selector.add_argument('file', nargs='?', help='path to script')
selector.add_argument('-m', help='module name')
parser.add_argument('args', nargs=argparse.REMAINDER)
parser.parse_args(['-m', 'hello', '--', 'arg1'])
运行这个产生
usage: test.py [-h] [-m M] [file] ...
test.py: error: argument file: not allowed with argument -m
这是有道理的,因为 argparse 似乎通常忽略选项的顺序 - 解析选项后剩余的任何位置参数都会按照指定从第一个到最后一个填充位置参数。
我已经尝试定义 customargparse.Action
来完成这项工作,但它最终看起来很 hacky,因为与Action
组中的一个参数相对应的类需要保存一个累积值以供以后包含在args
.
我也尝试过对 的输入进行预处理parser.parse_args
,但不喜欢这种方法,因为有关哪些选项具有值(以区分选项参数与file
参数)以及哪些选项是终端参数组的一部分的信息(应该考虑传递参数的开头[arg] ...
)将在argparse.add_argument
... 调用和预处理代码之间重复。
什么是一个好的方法(除了需要提供例如路径之外-f
)?
附加约束:
- 我更喜欢使用
argparse
或具有良好界面的东西,该界面将参数与帮助文本相关联并且不需要很长时间加载(对我来说,argparse 在 6 毫秒内导入) - 我只需要兼容 Python 3.6 及更高版本。
- 这并不理想,但
--
如果arg
后续参数(将传递给模块或文件)以 a 开头,-
或者可能被误认为[options]
.
解决方案
即使没有相互排斥的分组,file
也args
不能很好地一起玩:
In [2]: parser = argparse.ArgumentParser()
In [3]: parser.add_argument('-m');
In [4]: parser.add_argument('file', nargs='?');
In [6]: parser.add_argument('args', nargs=argparse.REMAINDER);
好的:
In [7]: parser.parse_args('-m foo a b c '.split())
Out[7]: Namespace(args=['b', 'c'], file='a', m='foo')
'--' 只是让我们使用 '-b' 作为纯字符串:
In [8]: parser.parse_args('-m foo a -- -b c '.split())
Out[8]: Namespace(args=['-b', 'c'], file='a', m='foo')
'a' 去 'file',休息到 'args' - 这是因为所有的 'contiguous' 位置都是一起评估的。使用remainder
,该-m
标志将被忽略,并被视为纯字符串。
In [9]: parser.parse_args('a -m foo -- -b c '.split())
Out[9]: Namespace(args=['-m', 'foo', '--', '-b', 'c'], file='a', m=None)
In [10]: parser.parse_args('a -- -b c '.split())
Out[10]: Namespace(args=['-b', 'c'], file='a', m=None)
参数分配甚至在Action
调用之前就发生了,因此自定义 Action 类不会改变这种行为。
标记参数为您提供最好的控制 - 对顺序和互斥性。
推荐阅读
- c++ - 在 C++ 中为每个可变参数宏参数添加一个函数参数的名称
- android - 如何修复这个 AndroidANR?
- asp.net-core-webapi - 每个操作方法的策略相同但所需参数不同
- javascript - 如果我第二次插入 DIV,它只会重叠,JS 将不再工作
- gradlew - 父项目pitest失败,但如果单独执行子项目运行良好
- android - 带有 Firebase 的 Android 未收到来自 Node.js Firebase 应用程序的通知
- jestjs - 玩笑因 SyntaxError 失败:意外的令牌 {
- javascript - 如何在 Angular 5 中使用 javaScript TimeSheet 插件
- elasticsearch - 安装elasticsearch老版本1.3
- javascript - Axios 发布待定