2010-08-11 2 views
11

В настоящее время мой код выглядит так. Это позволяет мне анализировать несколько параметров, которые получает мой скрипт программы. Есть ли другой подход, который ближе к «лучшим практикам»? Я не видел код, фактически использующий вывод argparse, только как его настроить.Использование вывода argparse для вызова функций

def useArguments(): 
    x = 0 
    while x <= 5: 
     if x == 0:      
      if args.getweather != None: 
       getWeather(args.getweather) 
     if x == 1: 
      if args.post != None: 
       post(args.post) 
     if x == 2: 
      if args.custompost != None: 
       custompost(args.custompost) 
     if x == 3: 
      if args.list != None: 
       listAccounts(args.list) 
     if x == 4: 
      if args.add != None: 
       addAccount(args.add[0]) 
     if x == 5: 
      if args.edit != None: 
       editAccount(args.edit[0]) 
     x = x + 1  


if __name__ == '__main__': 

    updateConfig() 

    parser = argparse.ArgumentParser(description='Post Yahoo weather to Twitter.', epilog="Report any bugs to [email protected]", prog='Program') 

    parser.add_argument('-a', '--add', nargs=1, help='Add a new account. Use the desired account name as an argument.') 
    parser.add_argument('-e', '--edit', nargs=1, choices=accountListSTR[:-1], help='Edit an account. Use the desired account name as an argument.') 
    parser.add_argument('-g', '--getweather', nargs='*', choices=accountListSTR, help='Get weather and post here. Specify account(s) as argument. Use "all" for all accounts. If you specify multiple accounts, separate by a space NOT a comma.') 
    parser.add_argument('-p', '--post', nargs='*', choices=accountListSTR, help='Post weather to Twitter. Specify account(s) as argument. Use "all" for all accounts. If you specify multiple accounts, separate by a space NOT a comma.') 
    parser.add_argument('-c', '--custompost', nargs=2, help='Post a custom message. Specify an account then type the message. Make sure you use "" around the message. Use "all" for all accounts.') 
    parser.add_argument('-l', '--list', action='store_const', const='all', help='List all accounts.') 
    parser.add_argument('--version', action='version', version='%(prog)s 0.3.3') 

    args = parser.parse_args() 

    useArguments() 

ответ

11

Вы могли бы поставить пользовательские action для аргумента, и я цитирую:

передавая объект, который реализует Действие API. Самый простой способ сделать это - это расширение argparse.Action, , подающего соответствующий метод __call__ . Метод __call__ должен принимать четыре параметра:

  1. парсер: объект ArgumentParser, который содержит это действие.
  2. namespace: Объект пространства имен, который будет возвращен parse_args(). Большинство действий добавляют к этому объекту атрибут.
  3. значение:. Ассоциированная командная строка арг, с любым типом-преобразованием применяется (Type-преобразования задаются с аргументом типа ключевого слова с add_argument()
  4. option_string:. Строка опции, которая была использована для вызова . это действие по option_string аргумент является необязательным, и будет отсутствовать, если действие связанно с позиционным аргументом
+0

В каких ситуациях это будет лучший метод? Я не вижу возможности использовать весь этот дополнительный код. Но опять же, я едва использовал Классы, поэтому я, вероятно, что-то пропустил. – avacariu

+1

@ vlad, он может быть использован для автоматического вызова функции при подаче аргумента, что и делает то, что вы делаете, и все ваши шаблоны - вам просто нужно сделать эти функции «методами __call__» соответствующих подклассов 'argparse.Action'. Но если вы не «получите» объектно-ориентированное программирование, это нормально, вы можете сделать это по-своему (хотя этот цикл и «если x ==» проверки действительно избыточны в любом случае - просто один за другим проверяет для каких аргументов присутствуют, возможно, последователи соответствующих вызовов, в другом используемом шаблоне нет добавленной стоимости). –

+0

Принял этот ответ, потому что он отвечает на мой вопрос. Я * могу * в конечном итоге попробовать это, чтобы узнать, как это работает; но это потребует много изменений в том, как работает мой код (особенно перечисленные там функции). Спасибо! – avacariu

4

За исключением --version, что очень часто вариант, действия вы Обеспечиваются лучше рассматривать как «подкомандами».

Я не знаю о argparse специфики, поскольку у меня есть еще попробовать Python 2.7, но вы можете взглянуть на svn команд в качестве примера, вот некоторые псевдокоды для командной строки:

myprog [--version] <command> [<command opts>...] 

Где <command> в:

add|edit|getweather|post|custompost|list 

И <command opts> варианты, специфичные для этой команды. Использование optparse (что похоже), то это будет означать, что ваша команда будет возвращена в args, при вызове parse_args, что позволяет сделать что-то вроде этого:

opts, args = parser.parse_args() 
if opts.version: 
    ... 
else: 
    getattr("do_" + args[0])(*args[1:]) 

Я нахожу эту модель особенно полезна для отладки, где я 'd обеспечить доступ к внутренним функциям из командной строки и передать различные аргументы для тестирования. Отрегулируйте выбор обработчика команд в соответствии с вашим собственным проектом.

+0

'argparse' фактически обеспечивает поддержку именно этого шаблона. ('optparse' не делает.) Я все еще застрял на Python 2.6, поэтому я тоже не знаю специфики, но они объясняются в [документации] (http://docs.python.org/ библиотека/argparse.html # суб-команд). –

+0

Каково было бы это сделать, а не просто удалять '--' из моих аргументов. Я догадываюсь, что конечный пользователь будет выглядеть так же, верно? Я предполагаю, что, имея это, это создало бы больше смысла для пользователя, а также b/c, что они не запускают программу с пользовательскими параметрами, а говорят, что она что-то делает. – avacariu

+0

@ vlad003: Правильно. Пользователь программы должен выбрать один и только один из этих «опций», так что действительно они являются командами для вашей программы. Однако эти команды потенциально могут принимать аргументы. Альтернативой является писать отдельные исполняемые скрипты для каждой команды, выполнять разбор парсеров в каждом из них и вызывать общую базу кода для реализации. Например, ваши сценарии могут быть вызваны: myprog-list, myprog-add и т. Д. Однако я мог бы добавить, поскольку вы используете argparse из Python-2.7, что в этом может быть очень интересная обработка аргументов. –

6

См http://docs.python.org/library/argparse.html#sub-commands:.

Одним из особенно эффективных способов обработки подкоманд является объединение использования метода add_subparsers() с вызовами set_defaults(), чтобы каждый подпараметр знал, какую функцию Python он должен выполнить.

В двух словах:

parser = argparse.ArgumentParser() 
subparsers = parser.add_subparsers() 

weather_parser = subparsers.add_parser('get-weather') 
weather_parser.add_argument('--bar') 
weather_parser.set_defaults(function=get_weather) # ! 

args = parser.parse_args(['get-weather', '--bar', 'quux']) 
print args.function(args) 

Здесь мы создаем subparser для команды get-weather и назначить функцию get_weather к нему.

Обратите внимание, что в документации указано, что ключевое слово/атрибут имеет имя func, но это определенно function с аргументом argparse 1.1.

Полученный код немного слишком многословен, поэтому я опубликовал небольшой пакет "argh", что делает вещи проще, например:

parser = argparse.ArgumentParser() 
add_commands(parser, [get_weather]) 
print dispatch(parser, ['get-weather', '--bar', 'quux']) 

«ARGH» может сделать больше, но я дам стеку переполнение ответа, , :-)

+2

Относительно недавнего редактирования caffinatedmonkey («Я не позволю этому переполнению переполнения ответов» → «Я дам ответ на переполнение стека»). Новая версия звучит отлично, но я на самом деле имел в виду, что ответ будет раздутым, если бы я наполнил слишком много информации в текстовое поле. =) –

+0

Вы уверены, что функция 'func' /' function' по-прежнему верна? 'func' отлично работает для меня ... –

+0

Не только подход subparsing уродливый, но, похоже, просто передаёт задачу синтаксического анализа аргументов на более низкий уровень - вам либо нужно иметь отдельные функции для передачи в каждый' func' который затем называет ваши «настоящие» функции, или ваши реальные функции должны принимать общие аргументы args. Я думаю, что первое прекрасно подходит для больших программ, но смешно вводить так много дополнительных слоев в небольшую программу.Тем не менее, подпарамеры кажутся лучшим вариантом. –