python + argparse - как получить порядок необязательных аргументов из командной строки - PullRequest
2 голосов
/ 12 октября 2011

Я хотел бы знать, как получить порядок необязательного аргумента, передаваемого из командной строки в 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 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')

Есть ли способ упорядочить их по позиции в строке командной строки или получить их индекс?

Ответы [ 3 ]

4 голосов
/ 12 октября 2011

Вы всегда можете посмотреть на sys.argv, который является списком (и, таким образом, упорядоченным) и просто перебрать его, проверяя, какой аргумент стоит первым, или использовать list.index(), чтобы увидеть соответствующие позиции ваших ключевых слов в списке ...

sys.argv содержит список слов, введенных в командной строке (разделителем такого «слова» является пробел, если строка не заключена в кавычки). Это означает, что если пользователь введет что-то вроде ./my_proggie -resize 500, тогда sys.argv будет содержать такой список: ['./my_proggie', '-resize', '500'].

2 голосов
/ 26 июля 2013

Пространство имен - это простой объект, чьи 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 для управления отображением атрибутов.

Другой вариант - использовать пользовательский класс Action.который создает этот 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)
1 голос
/ 06 ноября 2017

Я адаптировал подход из 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:» ... вы получаете только каждый используемый аргумент правильное количество раз.

...