这是我整理的一个简单的技巧,可能是一个合理的起点:
import argparse
class PositionalAction(argparse.Action):
def __call__(self,parser,namespace,values,option_string=None):
lst = getattr(namespace,self.dest)
lst.append(values)
parser.last_positional_values = lst
all_positional = getattr(namespace,'all_positional',[])
all_positional.append(lst)
namespace.all_positional = all_positional
class AssociateAction(argparse.Action):
def __call__(self,parser,namespace,values,option_string=None):
try:
parser.last_positional_values.append(values)
except AttributeError:
pass
parser = argparse.ArgumentParser()
parser.add_argument('-o',action=AssociateAction,dest=argparse.SUPPRESS)
junk,unknown = parser.parse_known_args()
for i,_ in enumerate(unknown):
parser.add_argument('arg%d'%i,action=PositionalAction,default=[])
print parser.parse_args()
它正在发挥作用:
temp $ python test1.py foo -o 1 bar -o 2 baz qux -o 4
Namespace(all_positional=[['foo', '1'], ['bar', '2'], ['baz'], ['qux', '4']], arg0=['foo', '1'], arg1=['bar', '2'], arg2=['baz'], arg3=['qux', '4'])
这个问题有一些挑战。首先,您想接受任意数量的位置参数—— argparse 不喜欢这样。 argparse 想预先知道会发生什么。解决方案是构建解析器并解析命令行,但告诉 argparse 仅解析已知参数(在这种情况下,非位置 -o 参数都被静默解析,但“位置”参数不被解析.)。 parse_known_args 非常适合此操作,因为它以 (namespace_of_parsed_stuff, uknown_args) 的形式返回一个元组。所以现在我们知道了未知的参数——我们只需要为每个解析器添加一个位置参数来让 parse_args 满意。
现在,自定义操作实际上在做什么?当找到位置参数时(在第二遍),我们得到默认值(这是一个列表)并将值添加到该列表中(以下我将其称为“值”列表)。然后我们使用对“值”列表的引用来修改 解析器。我们还从命名空间中获取“all_positional”列表。如果它没有那个属性,我们只会得到一个空列表。我们将“value”列表添加到“all_positional”列表中,并将其放回命名空间。
现在,当我们点击-o 标志时,我们查看解析器以获取“值”列表,并将附加值添加到该列表中。我们可以在完全不接触解析器的情况下做同样的事情......(我们可以查看namespace.all_positional[-1] -- 它与parser.last_positional_values 是同一个列表)。