我想知道如何获得从命令行传递到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')
有没有办法按命令行字符串中的位置排序或获取索引?
答案 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