5

我想知道如何获取从命令行传递给 argparse 的可选参数的顺序

我有图像处理类,它能够对图像应用不同的操作——比如旋转、裁剪、调整大小......

应用这些操作的顺序通常很重要(例如:您想在调整图像大小之前裁剪图像)

我有这个代码:

parser = argparse.ArgumentParser(description='Image processing arguments')

parser.add_argument('source_file', help='source file')
parser.add_argument('target_file', help='target file')

parser.add_argument('-resize', nargs=2, help='resize image', metavar=('WIDTH', 'HEIGHT'))
parser.add_argument('-rotate', nargs=1, help='rotate image', metavar='ANGLE')
parser.add_argument('-crop', nargs=4, help='crop image', metavar=('START_X','START_Y','WIDTH','HEIGHT'))

ar = parser.parse_args()

print ar

但是 - 无论我以哪种顺序将参数传递给脚本:

cmd.py test.jpg test2.jpg -crop 10 10 200 200 -resize 450 300

cmd.py test.jpg test2.jpg -resize 450 300 -crop 10 10 200 200

在命名空间中的项目总是按相同的顺序排列(我想是按字母顺序排列的):

Namespace(crop=['10', '10', '200', '200'], resize=['450', '300'], rotate=None, source_file='test.jpg', target_file='test
2.jpg')

有没有办法按命令行字符串中的位置对它们进行排序或获取它们的索引?

4

4 回答 4

5

您总是可以查看sys.argv哪个是列表(并因此排序)并简单地对其进行迭代,检查哪个参数先出现或使用list.index()来查看您的关键字在列表中的相应位置......

sys.argv包含在命令行中输入的单词列表(这种“单词”的分隔符是空格,除非字符串被引号括起来)。这意味着如果用户输入了类似./my_proggie -resize 500thensys.argv的内容,则将包含这样的列表:['./my_proggie', '-resize', '500'].

于 2011-10-12T09:20:35.463 回答
3

Namespace 是一个简单的对象,str()它根据其__dict__. 属性用 设置setattr(namespace, dest, value)

一种解决方案是定义一个自定义命名空间类。例如:

class OrderNamespace(argparse.Namespace):
    def __init__(self, **kwargs):
        self.__dict__['order'] = []
        super(OrderNamespace, self).__init__(**kwargs)
    def __setattr__(self,attr,value):
        self.__dict__['order'].append(attr)
        super(OrderNamespace, self).__setattr__(attr, value)

并使用

args = parser.parse_args(None, OrderNamespace())

为你的两个例子制作

OrderNamespace(crop=..., order=[..., 'crop', 'resize'], resize=...)
OrderNamespace(crop=..., order=[..., 'resize', 'crop'], resize=...)

order属性给出了设置其他属性的顺序。初始项目用于默认值和文件位置。添加default=argparse.SUPPRESS到参数将抑制其中一些项目。这个自定义类可以更精细,例如使用 OrderedDictionary,只注意所选参数的顺序,或order用于控制属性的显示。

另一种选择是使用创建此order属性的自定义 Action 类,例如

class OrderAction(argparse._StoreAction):
    def __call__(self, parser, namespace, values, option_string=None):
        setattr(namespace, self.dest, values)
        order = getattr(namespace, 'order') if hasattr(namespace, 'order') else []
        order.append(self.dest)
        setattr(namespace, 'order', order)
于 2013-07-25T20:31:44.580 回答
2

我改编了 hpaulj 的方法:

    class OrderNamespace(argparse.Namespace):
        def __init__(self, **kwargs):
            self.__dict__['order'] = []
            super(OrderNamespace, self).__init__(**kwargs)
        def __setattr__(self,attr,value):
            if value:
              self.__dict__['order'].append(attr)
            super(OrderNamespace, self).__setattr__(attr, value)


    parser.add_argument('-g',action='append',default=argparse.SUPPRESS,help='some action')

通过添加“if value:” ...您只能获得每个使用的参数正确的次数。

于 2017-11-06T16:52:11.220 回答
2

@Martin的解决方案存在问题:它不适用于以下情况:

parser.add_argument('-s', '--slong', action='store_false')

这是我的解决方案:

import argparse

class OrderedNamespace(argparse.Namespace):
    def __init__(self, **kwargs):
        self.__dict__["_order"] = []
        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):
        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
于 2019-11-22T22:51:53.903 回答