许多命令行实用程序为双破折号后的所有参数提供特殊处理 (
--
)。例子:
git diff
:--
之后的所有参数都是路径(可以以-
开头):
git diff [options] -- [path...]
一些包装器工具使用它来将任意参数传递给它们正在包装的工具——甚至是可能与它们自己的参数冲突的参数!
foowrap -a -- -a
🠡 🠡
│ └─── Passed to wrapped tool
└───────── Consumed by wrapper
argparse
来实现这一点?
您可以使用
nargs=argparse.REMAINDER
添加参数来捕获其余参数。
parser = argparse.ArgumentParser()
# other arguments...
parser.add_argument('remaining', nargs=argparse.REMAINDER)
args = parser.parse_args()
# use args.remaining...
也可以使用 nargs='*'
,这不会包括列表中的前导 --
。
似乎
argparse
(特别是parse_known_args()
已经原生支持这一点,尽管没有明确记录:
import argparse
p = argparse.ArgumentParser()
p.add_argument("-a", action="store_true")
p.add_argument("-b", action="store_true")
args, extra = p.parse_known_args()
print(f"args: {args}")
print(f"extra: {extra}")
$ python3 known.py -a -- -a -b
args: Namespace(a=True, b=False)
extra: ['--', '-a', '-b']
我们可以看到:
-a
之后的--
出现在extra
-b
之后的--
出现在extra
中并且未在命名空间中设置b=True
如果想忽略
--
分隔符,可以将其过滤掉:
extra = [a for a in extra if a != "--"]
我实际上在尝试编写“什么不起作用”示例时发现了这一点。因为从文档中这对我来说并不明显,所以我还是决定询问+回答。
我刚刚偶然发现了这个问题。我通过在 argparse 看到它们之前删除“--”参数来解决它。
# Extract underlying ("--") args before argparse parsing
for idx, arg in enumerate(argv):
if arg == "--":
wrapper_program_args = argv[:idx]
underlying_tool_args = argv[idx + 1:]
break
else:
wrapper_program_args = argv
underlying_tool_args = None
args = parser.parse_args(wrapper_program_args)
args.underlying_tool_args = underlying_tool_args
如果您希望帮助消息包含“--”选项,您可以提供自定义格式化程序。
# Customer formatter required to print help message for "--" option.
class CustomHelpFormatter(argparse.HelpFormatter):
def format_help(self):
original_help = super().format_help()
return original_help + " --\t\t\tArguments to pass to underlying tool. \n"
parser = argparse.ArgumentParser(formatter_class=CustomHelpFormatter)