argparse参数顺序

flo*_*pit 17 python arguments kwargs argparse

我有一点问题.

argparse用来解析我的论点,而且它运作得很好.

有了args,我这样做:

p_args = parser.parse_args(argv)
args = dict(p_args._get_kwargs())
Run Code Online (Sandbox Code Playgroud)

但问题p_args是我不知道如何通过它们在命令行中的位置来排序这些参数,因为它是一个字典.

那么有没有可能在命令行中按顺序在元组/列表/有序字典中包含参数?

jte*_*ace 14

为了保持参数的排序,我使用这样的自定义操作:

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)
Run Code Online (Sandbox Code Playgroud)

要使用它,例如:

>>> parser.parse_args(['--test2', '2', '--test1', '1'])
Namespace(ordered_args=[('test2', '2'), ('test1', '1')], test1=None, test2=None)
Run Code Online (Sandbox Code Playgroud)


小智 6

这有点脆弱,因为它依赖于理解 的内部结构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
Run Code Online (Sandbox Code Playgroud)

argparse.ArgumentParser.parse_known_args一旦为每个参数设置默认值,这将通过贯穿整个选项列表的知识来实现​​。这意味着用户指定的参数在第一次__setattr__遇到之前见过的参数时开始。

用法:

options, extra_args = parser.parse_known_args(sys.argv, namespace=OrderedNamespace())
Run Code Online (Sandbox Code Playgroud)

您可以检查options._arg_order用户指定的命令行参数的顺序,或者使用options._latest_of("arg1", "arg2")来查看稍后在命令行上指定的哪个--arg1--arg2哪个(出于我的目的,这就是我所需要的:查看两个选项中哪一个将是最重要的)。

更新:必须添加_finalize方法来处理sys.argv()列表中不包含任何参数的病态情况)

  • 好吧,只有在搞乱了我的重构并运行了一堆测试之后,我才意识到这在 action='store_const' 或 action='store_true' 等情况下根本不起作用......带有 add_argument 的东西('-f', action='store_true') 不会将 -f 添加到参数顺序列表中,因为 argparse 在遇到实际参数之前不会向命名空间添加任何值,除非使用 'const' 或 'default' 参数传递给add_argument。BAH,这本来可以是一个如此优雅的解决方案.. (2认同)

srg*_*erg 5

如果您需要知道参数在解析器中出现的顺序,您可以像这样设置解析器:

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
Run Code Online (Sandbox Code Playgroud)

这是运行此代码的快速示例:

$ python s.py --optional1 X --optional2 Y 1 2 3 4 5
['1', '2', '3', '4', '5']
Run Code Online (Sandbox Code Playgroud)

请注意,这args.positionals是一个按顺序排列位置参数的列表。有关更多信息,请参阅argparse 文档

  • 我认为这种方法的一个后果是 argparse 不能/不会对 1,2,3,4,5 进行任何验证(即强制用户仅输入 option2 的合法值)。您必须在代码中运行Optional2 的值并验证它们。 (2认同)