Это немного хрупко, поскольку полагается на понимание внутренних элементов 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()
, не содержащего аргументов в списке)