我有一个小问题。
我使用 argparse
来解析我的参数,它运行得非常好。
要获得这些参数,我做了以下操作:
p_args = parser.parse_args(argv)
args = dict(p_args._get_kwargs())
不过 p_args
的问题在于我不知道如何按照命令行中它们的位置获取这些参数,因为它是一个字典。
那么有没有可能按照命令行中它们的顺序将这些参数放入元组/列表/有序字典中呢?
我有一个小问题。
我使用 argparse
来解析我的参数,它运行得非常好。
要获得这些参数,我做了以下操作:
p_args = parser.parse_args(argv)
args = dict(p_args._get_kwargs())
不过 p_args
的问题在于我不知道如何按照命令行中它们的位置获取这些参数,因为它是一个字典。
那么有没有可能按照命令行中它们的顺序将这些参数放入元组/列表/有序字典中呢?
import argparse
class CustomAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
if not 'ordered_args' in namespace:
setattr(namespace, 'ordered_args', [])
previous = namespace.ordered_args
previous.append((self.dest, values))
setattr(namespace, 'ordered_args', previous)
parser = argparse.ArgumentParser()
parser.add_argument('--test1', action=CustomAction)
parser.add_argument('--test2', action=CustomAction)
例如,要使用它:
>>> parser.parse_args(['--test2', '2', '--test1', '1'])
Namespace(ordered_args=[('test2', '2'), ('test1', '1')], test1=None, test2=None)
import argparse
parser = argparse.ArgumentParser(description = "A cool application.")
parser.add_argument('--optional1')
parser.add_argument('positionals', nargs='+')
parser.add_argument('--optional2')
args = parser.parse_args()
print args.positionals
$ python s.py --optional1 X --optional2 Y 1 2 3 4 5
['1', '2', '3', '4', '5']
args.positionals
是一个按顺序排列的位置参数列表。有关更多信息,请参阅argparse文档。这个方法有点脆弱,因为它依赖于对argparse.ArgumentParser
的内部了解,但是如果不想重写argparse.ArgumentParser.parse_known_args
的话,我会使用以下方法:
class OrderedNamespace(argparse.Namespace):
def __init__(self, **kwargs):
self.__dict__["_arg_order"] = []
self.__dict__["_arg_order_first_time_through"] = True
argparse.Namespace.__init__(self, **kwargs)
def __setattr__(self, name, value):
#print("Setting %s -> %s" % (name, value))
self.__dict__[name] = value
if name in self._arg_order and hasattr(self, "_arg_order_first_time_through"):
self.__dict__["_arg_order"] = []
delattr(self, "_arg_order_first_time_through")
self.__dict__["_arg_order"].append(name)
def _finalize(self):
if hasattr(self, "_arg_order_first_time_through"):
self.__dict__["_arg_order"] = []
delattr(self, "_arg_order_first_time_through")
def _latest_of(self, k1, k2):
try:
print self._arg_order
if self._arg_order.index(k1) > self._arg_order.index(k2):
return k1
except ValueError:
if k1 in self._arg_order:
return k1
return k2
这是通过了解 argparse.ArgumentParser.parse_known_args
会遍历整个选项列表一次,并为每个参数设置默认值来实现的。这意味着用户指定的参数从第一次__setattr__
命中它之前的参数开始。
用法:
options, extra_args = parser.parse_known_args(sys.argv, namespace=OrderedNamespace())
options._arg_order
以查看用户指定的命令行参数的顺序,或者使用options._latest_of("arg1", "arg2")
来查看在命令行上后面指定的是--arg1
还是--arg2
(这正是我需要的:看到两个选项中哪一个会被覆盖)。更新:必须添加_finalize
方法来处理sys.argv()
列表中不包含任何参数的病态情况。import collections
from argparse import ArgumentParser
class SortedArgumentParser():
def __init__(self, *args, **kwargs):
self.ap = ArgumentParser(*args, **kwargs)
self.args_dict = collections.OrderedDict()
def add_argument(self, *args, **kwargs):
self.ap.add_argument(*args, **kwargs)
# Also store dest kwarg
self.args_dict[kwargs['dest']] = None
def parse_args(self):
# Returns a sorted dictionary
unsorted_dict = self.ap.parse_args().__dict__
for unsorted_entry in unsorted_dict:
self.args_dict[unsorted_entry] = unsorted_dict[unsorted_entry]
return self.args_dict
add_argument
方法应该具有与原始的ArgumentParser
完全相同的功能。缺点是,如果您想要其他方法,您将不得不为所有这些方法编写包装。幸运的是,我只使用了add_argument
和parse_args
,所以这对我来说非常好用。如果您想使用父ArgumentParser
,则需要做更多的工作。https://github.com/claylabs/ordered-keyword-args
def multiple_kwarguments(first , **lotsofothers):
print first
for i,other in lotsofothers:
print other
return True
multiple_kwarguments("first", second="second", third="third" ,fourth="fourth" ,fifth="fifth")
输出:
first
second
fifth
fourth
third
from orderedkwargs import ordered kwargs
@orderedkwargs
def mutliple_kwarguments(first , *lotsofothers):
print first
for i, other in lotsofothers:
print other
return True
mutliple_kwarguments("first", second="second", third="third" ,fourth="fourth" ,fifth="fifth")
输出:
first
second
third
fourth
fifth
这是我基于现有解决方案的简单解决方案:
class OrderedNamespace(argparse.Namespace):
def __init__(self, **kwargs):
self.__dict__["_order"] = [None]
super().__init__(**kwargs)
def __setattr__(self, attr, value):
super().__setattr__(attr, value)
if attr in self._order:
self.__dict__["_order"].clear()
self.__dict__["_order"].append(attr)
def ordered(self):
if self._order and self._order[0] is None:
self._order.clear()
return ((attr, getattr(self, attr)) for attr in self._order)
parser = argparse.ArgumentParser()
parser.add_argument('--test1', default=1)
parser.add_argument('--test2')
parser.add_argument('-s', '--slong', action='store_false')
parser.add_argument('--test3', default=3)
args = parser.parse_args(['--test2', '2', '--test1', '1', '-s'], namespace=OrderedNamespace())
print(args)
print(args.test1)
for a, v in args.ordered():
print(a, v)
输出:
OrderedNamespace(_order=['test2', 'test1', 'slong'], slong=False, test1='1', test2='2', test3=3)
1
test2 2
test1 1
slong False
它允许在add_argument()中执行操作,这对于定制的操作类解决方案更加困难。