2012-01-26 2 views
23

У меня небольшая проблема с argparse. У меня есть опция xlim, которая является xrange участка. Я хочу иметь возможность передавать номера, такие как -2e-5. Однако это не сработает - argparse интерпретирует это позиционный аргумент. Если я делаю -0.00002, он работает: argparse читает это как отрицательное число. Возможно ли иметь возможность читать в -2e-3?Python Argparse: проблема с необязательными аргументами, которые являются отрицательными числами

код ниже, и пример того, как я бы запустить это:

./blaa.py --xlim -2.e-3 1e4 

Если я следующее работает:

./blaa.py --xlim -0.002 1e4 

Код:

parser.add_argument('--xlim', nargs = 2, 
        help = 'X axis limits', 
        action = 'store', type = float, 
        default = [-1.e-3, 1.e-3]) 

Хотя я могу заставить его работать таким образом, я бы очень хотел использовать научную нотацию. У кого-нибудь есть идеи?

Приветствия

+0

Помогает ли цитирование '-2e-5'? – nmichaels

+0

В соответствии с http://code.google.com/p/argparse/issues/detail?id=37 он должен быть исправлен. Проверьте, является ли версия argparse у вас более новой или такой же. – favoretti

+0

@nmichaels Привет, вы имеете в виду «-2e-5»? К сожалению, это не работает, я думаю, что он все еще интерпретирует это как аргумент. Точная ошибка от './blah.py -xlim" -.2e-5 "1e5' isxx: ожидается 2 аргумента (ов). Если я использую \ - он думает, что это строка, а затем жалуется, потому что это должен быть float – Ger

ответ

11

Как уже отмечалось комментариями, проблема заключается в том, что - префикс обрабатывается в качестве опции вместо в качестве аргумента. Один из способов обойти это изменить префикс, используемый для вариантов с prefix_chars аргументом:

#!/usr/bin/python 
import argparse 

parser = argparse.ArgumentParser(prefix_chars='@') 
parser.add_argument('@@xlim', nargs = 2, 
        help = 'X axis limits', 
        action = 'store', type = float, 
        default = [-1.e-3, 1.e-3]) 
print parser.parse_args() 

Пример вывода:

$ ./blaa.py @@xlim -2.e-3 1e4 
Namespace(xlim=[-0.002, 10000.0]) 

Edit: В качестве альтернативы, вы можете продолжать использовать - в качестве разделителя, проходят xlim как единый значение и использовать функцию в type реализовать свой собственный синтаксический:

#!/usr/bin/python 
import argparse 

def two_floats(value): 
    values = value.split() 
    if len(values) != 2: 
     raise argparse.ArgumentError 
    values = map(float, values) 
    return values 

parser = argparse.ArgumentParser() 
parser.add_argument('--xlim', 
        help = 'X axis limits', 
        action = 'store', type=two_floats, 
        default = [-1.e-3, 1.e-3]) 
print parser.parse_args() 

Пример OUTP ут:

$ ./blaa.py --xlim "-2e-3 1e4" 
Namespace(xlim=[-0.002, 10000.0]) 
+0

Я действительно хотел сохранить' -' в качестве разделителя, поэтому я сделал грубый синтаксический анализ sys .argv, прежде чем я назову parse_args(). То, как я это делал, в комментарии выше, но ваш путь намного лучше. Благодаря! – Ger

3

Если вы до изменения argparse.py себя, вы могли бы изменить отрицательное число Искателя для обработки научной нотации:

В class _ActionsContainer.__init__()

self._negative_number_matcher = _re.compile(r'^-(\d+\.?|\d*\.\d+)([eE][+\-]?\d+)?$') 

Или после создания синтаксического анализатора, вы может установить значение parser._negative_number_matcher. Такой подход может иметь проблемы, если вы создаете группы или подпарамеры, но должны работать с простым парсером.

19

Один обходной путь, который я нашел, - это указать значение, но добавив пробел. То есть,

./blaa.py --xlim " -2.e-3" 1e4 

Таким образом argparse не будет думать -2.e-3 является именем параметра, так как первый символ не дефис тира, но он все равно будет преобразован правильно поплавок, потому что поплавок (строка) игнорирует пробелы слева.

+1

приятно! Работал для меня на совершенно другом языке/среде также –

+0

Я сделал небольшой препроцессор, который сканирует sys.argv для «xlim» и добавляет пробел в начало (через ваш ответ). Я поставил это перед вызовом argparse и, похоже, хорошо работает ... 'для indx в диапазоне (len (sys.argv) - 1): if 'xlim' в sys.argv [indx]: sys.argv [indx + 1] = '{0}'. format (sys.argv [indx + 1]) ' – jeremiahbuddha

+0

Это также работает в модуле argparse факела –

3

Вот код, который я использую. (Он похож на jeremiahbuddha, но он отвечает на вопрос более непосредственно, так как он имеет дело с отрицательными числами.)

Поместите это перед вызовом argparse.ArgumentParser()

for i, arg in enumerate(sys.argv): 
    if (arg[0] == '-') and arg[1].isdigit(): sys.argv[i] = ' ' + arg 
+0

Самый лучший и простой ответ для этой давней ошибки – mxmlnkn

2

Другой обходной путь будет проходить в аргументе, используя «=» символ в дополнение к ссылкой на аргумент - то есть, --xlim="-2.3e14"

1

Вдохновленный подход andrewfn, я создал отдельную вспомогательную функцию, чтобы сделать sys.argv пустячный:

def _tweak_neg_scinot(): 
    import re 
    import sys 
    p = re.compile('-\\d*\\.?\\d*e', re.I) 
    sys.argv = [' ' + a if p.match(a) else a for a in sys.argv] 

Регулярного выражения ищет:

  • -: отрицательный знак
  • \\d*: ноль или более цифр (для нестандартного форматирования значений как -.5e-2 или -4354.5e-6)
  • \\.?: дополнительный период (например, -2e-5 разумно)
  • \\d*: еще один набор из нуля или более цифр (для вещей, как -2e-5 и -7.e-3)
  • e: чтобы соответствовать экспоненте маркеру

re.I делает это соответствовать как -2e-5 и -2E-5. Использование p.match означает, что он выполняет поиск только с начала каждой строки.

0

Если указать значение для вашего варианта с знаком равенства, argparse не будет рассматривать его в качестве отдельной опции, даже если он начинается с -:

./blaa.py --xlim='-0.002 1e4' 
# As opposed to --xlim '-0.002 1e4' 

И если значение не имеет места в это, вы можете опустить кавычки:

./blaa.py --xlim=-0.002 

См: https://www.gnu.org/software/guile/manual/html_node/Command-Line-Format.html

с этим, нет необходимости писать вам r собственный type= парсер или переопределить символ префикса от - до @, как предполагает принятый ответ.

+0

Это не работает в этом конкретном случае, потому что --- xlim ожидает два аргумента (nargs = 2). То есть, если вы не хотите изменить соглашение, чтобы ваша программа _ запрашивала_ invoker для кодирования двух значений в виде одной строки, а ваша программа затем выполняет разделение. – itub

+0

Ах, хорошая точка @itub. Если 'nargs = 2' является требованием, и любое из двух значений параметра начинается с тире, тогда его не обойти. – mksios

Смежные вопросы