2015-05-14 4 views
4

Я пытаюсь выполнять математические операции между изображениями. Я определил (упрощенный вариант моего реального кода):Argparse: два позиционных аргумента с nargs = '+'

parser = argparse.ArgumentParser(description='Arithmetic operations on images') 
parser.add_argument("input1", metavar='input1', action='store', 
     help='list of input images to operate with', nargs="+", type=str) 
parser.add_argument("operation", metavar='operation', action='store', type=str, 
     help='type of operation (+,-,*,/) to be done', nargs=1) 
parser.add_argument("input2",metavar='input2', action='store', nargs="+", 
     type=str, help='image (or value) with which to perform the operation on input1') 

Этот код, производит:

arith.py -h 
usage: arith.py [-h] input1 [input1 ...] operation input2 [input2 ...] 

так же понимаю, что input1 может содержать один или несколько элементов, операция будет один один , а input2 может быть любым количеством элементов.

Проблема, конечно, состоит в том, что, имея два позиционных аргумента с неопределенным количеством элементов, argparse смущает то, что есть. Я попытался добавить опции = ["+", "-", "*", "/"] в "операцию", чтобы он знал, где провести разделение, но, похоже, argparse не может этого сделать. На самом деле, в argparse документации, говоря о «*» nargs = вы можете прочитать:

Обратите внимание, что, как правило, не имеет особого смысла, чтобы иметь больше, чем один позиционный аргумент с nargs = «*»

Я думал, что могу добавить вместе args.input1, args.operation и args.input2 и отделить себя от поиска «+», «-», «/», «*», но прежде чем делать что-то настолько уродливое. подумал о том, чтобы использовать коллективный ум.

+2

Я не уверен, что 'argparse' подходит для того, что вы здесь делаете. Вероятно, было бы проще просто перейти через 'sys.argv' напрямую. – khelwood

+0

Привет, Хелвуд. Собственно, я разбираю sys.argv, используя argparse. Это дает мне помощь для пользователя «бесплатно», и для меня все типы проверки и существующие переменные. Выполнение непосредственно sys.argv было бы подобно моему решению объединения пула ввода 1, работы и ввода2, а затем разделения. Возможность, но уродливая;). Спасибо, в любом случае! – Jblasco

+0

'argparse' может построить такое справочное сообщение, но это не значит, что он может фактически анализировать аргументы так, как вы хотите. Если я назвал 'arith.py a b c d e f g', какой из них' operation'? Это может быть любой из 'b' через' f'. 'argparse' не имеет встроенного шаблона отслеживания обратного отслеживания; он просто обрабатывает аргументы слева направо жадным способом. – chepner

ответ

0

Если вы использовали «обязательные необязательные» аргументы, вы могли бы сделать эту работу. Если в командной строке будут отображаться параметры при переключении с левых операндов на операцию на изменение операндов справа. например.

import argparse 

parser = argparse.ArgumentParser(description='Process some integers.') 
parser.add_argument("--left-operands", "-l", nargs="+", required=True) 
parser.add_argument("--right-operands", "-r", nargs="+", required=True) 
parser.add_argument("--operation", "-o", choices=["+", "-", "*", "/"], required=True) 

argline = "-l 1 2 -o + -r 3 4" 

print(parser.parse_args(argline.split(" "))) 
+0

Спасибо, Дюны, но не совсем то, что я искал. Я хочу, чтобы аргументы были позиционными. В противном случае я вернусь к идее ввода input1, input2 и операции вместе и разделения их внутри. – Jblasco

1

При выделении строки в positionals, анализатор различает только те, которые начинаются с префикса полукокса (например, «-») и все остальное. Он не может различать строки, которые представляют «числа» и единицы, которые представляют «операции». В действительности он выполняет эту операцию регулярок:

re.match('(A+)(A)(A+)','AAAAAAAAA') 

, который будет производить (AAAAAA),(A),(A). Он выделяет достаточное количество строк для последних двух групп, чтобы удовлетворить их спецификации, и выделяет остальное на первое.

Значит, вам нужен какой-то «флаг», чтобы отметить конец первого списка.

Это, я думаю, ближе вы получите с argparse:

parser.add_argument("input1", nargs="+", type=int) 
parser.add_argument("-o", "--operation", choices=['+','minus','*','/']) 
parser.add_argument("input2", nargs="+", type=int) 

, который должен превратить

PROG 1 3 4 -o + 5 6 7 
PROG 1 3 4 -o+ 5 6 7 
PROG 1 3 4 --operation=+ 5 6 7 

в (я думаю)

namespace(input1=[1,3,4], operation='+', input2=[5,6,7]) 

Обратите внимание, что список choices не включает '-'. Это потому, что парсер рассматривает это как prefix_char. Там может быть способ прокрасть его в качестве значения аргумента, но я не собираюсь тратить время, чтобы его найти.

Я преобразовал значения input1 в целые числа в синтаксическом анализаторе. Вы можете это сделать. И, конечно же, сделайте поплавки.

Я пропустил параметры по умолчанию, такие как type=str, action='store'.


Но, возможно, лучшим решением является принятие всех значений в виде 1 списка и разделение его на себя. По крайней мере, с этими тремя аргументами вы не пользуетесь большим количеством мощности argparse.

alist = ['1','2','3','+','4','5','6'] 
i = <find index of '+-/*'> 
input1 = alist[:i] 
operations = alist[i] 
input2 = alsits[i+1:] 
+0

Спасибо за внимание. Раньше единственный способ, которым я мог прокрасть «-» в непозиционный аргумент, - это: -o "-" так что строка с пробелом перед, так что - берется как часть строки – Jblasco

+0

Задание чего-то другого типа '#' как prefix_char, может освободить '-' для использования в качестве аргумента. – hpaulj

+0

Да, hpaulj, вот такой подход я последовал, как я намекал в OP. Кажется, я слишком много просил. Я просто оставил три аргумента, однако, для ясности для пользователей. После разбора я снова присоединился к ним и правильно разделил их. – Jblasco