python + argparse - 如何从命令行获取可选参数的顺序

时间:2011-10-12 09:15:47

标签: python argparse

我想知道如何获得从命令行传递到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 个答案:

答案 0 :(得分:4)

你总是可以偷看sys.argv这是一个列表(并因此被排序)并简单地迭代它,检查哪个参数首先出现,或者使用list.index()来查看关键字的相应位置。列表...

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

答案 1 :(得分:2)

命名空间是一个简单的对象,str()根据__dict__中键的顺序列出其属性。属性使用setattr(namespace, dest, value)设置。

一种解决方案是定义自定义Namespace类。例如:

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)

答案 2 :(得分:1)

我改编了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:”...您只能获得每个使用过的参数正确的次数。

答案 3 :(得分:0)

@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