Использование вывода argparse для вызовов

В настоящее время мой код выглядит так. Это позволяет мне анализировать несколько параметров, которые получает моя программа script. Есть ли другой подход, который ближе к "лучшим практикам"? Я не видел код, фактически использующий вывод 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()

Ответ 1

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

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

  • парсер: объект ArgumentParser, содержащий это действие.
  • namespace: объект пространства имен, который будет возвращен parse_args(). Большинство действий добавляют к этому объекту атрибут.
  • значения. Связанные аргументы командной строки с любыми применяемыми типами преобразованиями. (Тип-преобразования указаны с аргументом ключевого слова типа add_argument().
  • option_string: строка опций, которая использовалась для вызова этого действия. Параметр option_string является необязательным и будет отсутствовать, если действие связано с позиционным аргументом.

Ответ 2

См. 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)

Здесь мы создаем подпараметр для команды 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" может сделать больше, но я позволю переполнение стека ответить на это.: -)

Ответ 3

За исключением --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:])

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