我可以指示 Python 的 argparse 将位置 arg 之后的所有参数也视为位置参数,即使它们匹配可选 arg 吗?
Can I direct Python's argparse to treat all arguments after a positional arg as also positional, even if they match an optional arg?
我正在编写一个实用程序(称之为 runner
),作为其主要功能,运行 是另一个脚本。 运行 的脚本作为参数传递,以及应传递给脚本的任何参数。所以,例如:
runner script.py arg1 arg2
将 运行 script.py
作为子进程,以 arg1
和 arg2
作为参数。这很简单,使用以下内容:
parser = argparse.ArgumentParser()
parser.add_argument("script", help="The script to run")
parser.add_argument("script_args", nargs="*", help="Script arguments", default=[])
args = parser.parse_args()
复杂的是我有一些额外的参数传递给 runner
,它们修改了脚本的调用方式。其中之一是 --times
,它将用于确定 运行 脚本的次数。所以:
runner --times 3 script.py arg1 arg2
将 运行 script.py
三次,以 arg1
和 arg2
作为参数。
我要解决的问题是这样的。我希望在脚本名称之后的任何参数都被视为传递给脚本的参数,即使它们匹配runner
[=54=的参数名称].所以:
runner script.py arg1 arg2 --times 3
应该运行script.py一次,并传递参数arg1
、arg2
、--times
, 3
到 script.py.
我找不到任何方法告诉 ArgumentParser 将 script
arg 之后的所有参数都视为位置参数。
我知道脚本的调用者可以使用 --
special argument 强制执行此行为,因此以下将产生所需的行为:
runner -- script.py arg1 arg2 --times 3
但我希望程序改为处理此问题。这种行为可能吗?
首先,你不应该这样做。更清楚的是,如果您明确指出哪些参数适用于哪个程序(调用),也许您可以用引号将被调用脚本的整个脚本参数括起来,例如:
runner script.py "arg1 arg2 --times 3"
但如果您想按自己的方式执行此操作,则可以用自己的函数覆盖 ArgumentParser.parse_arguments
函数。我只是建立一个例子来说明它是如何可能的(对我来说它正在工作),但我不知道是否有任何副作用:
import argparse
from typing import Optional, Sequence
class ErrorCatchingArgumentParser(argparse.ArgumentParser):
def parse_args(self, args: Optional[Sequence[str]] = ...) -> argparse.Namespace:
ns, a = super().parse_known_args(args=args)
args.insert(args.index(ns.script), "--")
return super().parse_args(args=args)
if __name__ == '__main__':
arguments = ["--time", "3", "myscript", "my_args", "myargs2", "--time", "5"]
parser = ErrorCatchingArgumentParser()
parser.add_argument("script", help="The script to run")
parser.add_argument("--time", help="The script to run")
parser.add_argument("script_args", nargs="*", help="Script arguments", default=[])
print(arguments)
namespace = parser.parse_args(arguments)
print(arguments)
print(namespace)
输出:
['--time', '3', 'myscript', 'my_args', 'myargs2', '--time', '5']
['--time', '3', '--', 'myscript', 'my_args', 'myargs2', '--time', '5']
Namespace(script='myscript', time='3', script_args=['my_args', 'myargs2', '--time', '5'])
它
- 使用超类的
parse_known_args
解析给定的参数以获得所有参数集(并且不引发错误)
- 搜索您的
script
变量并在参数列表中在其前面插入 --
- 使用超类的
parse_args
函数解析参数以获得“真实”参数
在输出中您可以看到原始参数、操作参数和创建的命名空间。
但我认为无论如何你都不应该这样做。
我正在编写一个实用程序(称之为 runner
),作为其主要功能,运行 是另一个脚本。 运行 的脚本作为参数传递,以及应传递给脚本的任何参数。所以,例如:
runner script.py arg1 arg2
将 运行 script.py
作为子进程,以 arg1
和 arg2
作为参数。这很简单,使用以下内容:
parser = argparse.ArgumentParser()
parser.add_argument("script", help="The script to run")
parser.add_argument("script_args", nargs="*", help="Script arguments", default=[])
args = parser.parse_args()
复杂的是我有一些额外的参数传递给 runner
,它们修改了脚本的调用方式。其中之一是 --times
,它将用于确定 运行 脚本的次数。所以:
runner --times 3 script.py arg1 arg2
将 运行 script.py
三次,以 arg1
和 arg2
作为参数。
我要解决的问题是这样的。我希望在脚本名称之后的任何参数都被视为传递给脚本的参数,即使它们匹配runner
[=54=的参数名称].所以:
runner script.py arg1 arg2 --times 3
应该运行script.py一次,并传递参数arg1
、arg2
、--times
, 3
到 script.py.
我找不到任何方法告诉 ArgumentParser 将 script
arg 之后的所有参数都视为位置参数。
我知道脚本的调用者可以使用 --
special argument 强制执行此行为,因此以下将产生所需的行为:
runner -- script.py arg1 arg2 --times 3
但我希望程序改为处理此问题。这种行为可能吗?
首先,你不应该这样做。更清楚的是,如果您明确指出哪些参数适用于哪个程序(调用),也许您可以用引号将被调用脚本的整个脚本参数括起来,例如:
runner script.py "arg1 arg2 --times 3"
但如果您想按自己的方式执行此操作,则可以用自己的函数覆盖 ArgumentParser.parse_arguments
函数。我只是建立一个例子来说明它是如何可能的(对我来说它正在工作),但我不知道是否有任何副作用:
import argparse
from typing import Optional, Sequence
class ErrorCatchingArgumentParser(argparse.ArgumentParser):
def parse_args(self, args: Optional[Sequence[str]] = ...) -> argparse.Namespace:
ns, a = super().parse_known_args(args=args)
args.insert(args.index(ns.script), "--")
return super().parse_args(args=args)
if __name__ == '__main__':
arguments = ["--time", "3", "myscript", "my_args", "myargs2", "--time", "5"]
parser = ErrorCatchingArgumentParser()
parser.add_argument("script", help="The script to run")
parser.add_argument("--time", help="The script to run")
parser.add_argument("script_args", nargs="*", help="Script arguments", default=[])
print(arguments)
namespace = parser.parse_args(arguments)
print(arguments)
print(namespace)
输出:
['--time', '3', 'myscript', 'my_args', 'myargs2', '--time', '5']
['--time', '3', '--', 'myscript', 'my_args', 'myargs2', '--time', '5']
Namespace(script='myscript', time='3', script_args=['my_args', 'myargs2', '--time', '5'])
它
- 使用超类的
parse_known_args
解析给定的参数以获得所有参数集(并且不引发错误) - 搜索您的
script
变量并在参数列表中在其前面插入--
- 使用超类的
parse_args
函数解析参数以获得“真实”参数
在输出中您可以看到原始参数、操作参数和创建的命名空间。
但我认为无论如何你都不应该这样做。