Как анализировать позиционные аргументы с помощью знака минус (отрицательные числа) с помощью argparse

Я хотел бы проанализировать требуемый позиционный аргумент, содержащий список целых чисел, разделенных запятыми. Если первое целое число содержит знак минус ('-'), argparse жалуется:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('positional')
parser.add_argument('-t', '--test', action='store_true')
opts = parser.parse_args()
print opts

$ python example.py --test 1,2,3,4
Namespace(positional='1,2,3,4', test=True)

$ python example.py --test -1,2,3,4
usage: example.py [-h] [-t] positional
example.py: error: too few arguments

$ python example.py --test "-1,2,3,4"
usage: example.py [-h] [-t] positional
example.py: error: too few arguments

Я видел, что люди предлагают использовать какой-то другой символ, кроме -, как символ флага, но я бы предпочел не делать этого. Есть ли другой способ настроить argparse, чтобы позволить как --test, так и -1,2,3,4 в качестве допустимых аргументов?

Ответы

Ответ 1

Вам нужно вставить -- в аргументы командной строки:

$ python example.py --test -- -1,2,3,4
Namespace(positional='-1,2,3,4', test=True)

Двойная тире останавливает argparse, ища любые дополнительные опции; это стандартный метод defacto для обработки именно этого прецедента для инструментов командной строки.

Ответ 2

В документации :

Метод parse_args() пытается выдавать ошибки всякий раз, когда пользователь имеет явно допустил ошибку, но некоторые ситуации по своей сути неоднозначны. Например, аргумент командной строки -1 может быть либо попыткой указать опцию или попытку предоставить позиционный аргумент. Метод parse_args() здесь осторожен: позиционные аргументы могут начните только с - если они выглядят как отрицательные числа, и нет параметры в парсере, которые выглядят как отрицательные числа:

Так как -1,2,3,4 не выглядит как отрицательное число, вы должны "убежать" от него с помощью --, как в большинстве систем * nix.

Другим решением было бы использовать nargs для позиционирования и передавать числа в виде пробела:

#test.py
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('positional', nargs='*') #'+' for one or more numbers

print parser.parse_args()

Вывод:

$ python test.py -1 2 3 -4 5 6
Namespace(positional=['-1', '2', '3', '-4', '5', '6'])

Третий способ получить то, что вы хотите, это использовать parse_known_args вместо parse_args. Вы не добавляете позиционный аргумент в синтаксический анализатор и не анализируете его вручную:

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--test', action='store_true')

parsed, args = parser.parse_known_args()
print parsed
print args

Результат:

$ python test.py  --test -1,2,3,4                                            
Namespace(test=True)
['-1,2,3,4']    

Это имеет тот недостаток, что текст справки будет менее информативным.