这是我整理的一个简单的技巧,可能是一个合理的起点:
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
)。