2011-10-12 62 views
2

我想知道如何从命令行传递的可选参数的顺序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 450调整大小300

cmd.py测试.JPG test2.jpg调整大小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

你可以在sys.argv总是偷看这是一个列表(因此命令),并简单地遍历它检查哪个参数是第一位的,或使用list.index()看到列表中的关键字各自的立场...

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

2

命名空间是一个简单的对象,其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属性的自定义操作类,例如,

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) 
+0

OrderNamespace是一个很好的解决方案,如果一个人也想使用其他操作(例如builtins)。好想法! –

+0

不幸的是,当设置了默认值时,将调用所有默认值的__setattr__方法,但是它们是否被使用。 –

+0

如果您不使用'SUPPRESS',默认值将出现在'订单'列表的开头,也可能在结尾处再次出现。 'parser'使用相同的'__setattr__'来记录默认值和给定值。 'OrderAction'没有这个问题。 – hpaulj

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') 

通过添加“如果值:” ......你只能得到每一个使用的说法正确的次数。

+0

这个效果更好 – ddofborg