Разбор параметров командной строки в Python

Разбор параметров командной строки в Python

При создании консольных программ в Python очень часто необходимо разобрать параметры (аргументы) передаваемые через командную строку, это можно сделать используя переменную argv из модуля sys, а так же с помощью модуля argparse из стандартной библиотеки Pyhton.

Второй способ более предпочтительный и удобный, далее ему мы уделим больше внимания.

Статья ниже не является полным описание всех возможностей модуля argparse, это просто общий обзор.

Ниже я иногда пишу аргументы командной строки, иногда параметры командной строки… Имеется ввиду одно и тоже 🙂

Получение параметров без использования argparse

Например, мы хотим написать программу после запуска выводящую в консоль «Привет <переданное_имя>». Имя мы будем передавать через параметр в командной строке, далее его нужно получить в нашей программе. Как это сделать?

Мы можем сделать это используя стандартный модуль sys и его переменную argv, она содержит список переданных параметров (нулевой элемент списка содержит имя нашего скрипта).

Другими словами, чтобы вывести имя, которое мы передаем аргументом, необходимо обратиться к  sys.argv[1]:

import sys
print(f'Привет {sys.argv[1]}')

Сохраним код в файле hello.py и запустим его с параметром «Александр» (аргументом):

python hello.py Александр

Получаем ожидаемое:

Привет Александр

Но если попытаться запустить скрипт без параметра, то получаем ошибку поскольку в списке нет элемента с индексом 1. Исправим это сделав проверку на наличии передаваемого параметра и если он не передается, будет выводиться «Привет мир!»

import sys

if len(sys.argv) == 1:
    print('Привет мир!')
else:
    print(f'Привет {sys.argv[1]}')

Теперь немного усложним задачу, что если мы хотим передавать имя с помощью именованного параметра —name, доработаем наш код:

import sys

if len(sys.argv) == 1:
    print('Привет мир!')
else:
    p_name = sys.argv[1]
    p_value = sys.argv[2]

    if p_name == '--name':
        print(f'Привет {p_value}')
    else:
        print(f'Неизвесный параметр {p_name}')

Запустив скрипт таким образом:

python hello.py --name Александр

Получаем нужный результат, если в место «—name» передать другое значение, то получаем предупреждение.

Но, если мы передадим один параметр вместо двух, то скрипт не запуститься, нам необходимо добавить еще один if для проверки существование минимум двух параметров.

А если нам нужно добавить еще несколько параметров, а если не все из них обязательные… короче код начнется превращаться в ужас, вот здесь нам на помощь и придет модуль argparse стандартной питоновской библиотеки.

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

Этот модуль облегчит нам разбор и дальнейшее использование передаваемых скрипту аргументов из командной строки.

Начнем переписывать наш пример:

import argparse

parser = argparse.ArgumentParser()

parser.add_argument('name', nargs='?', default='мир!')

args = parser.parse_args()

print(f'Привет {args.name}')

Сохраним код в новый файл hello2.py и выполним передав ему в качестве параметра «Александр»:

python hello2.py Александр

Мы получим то, что требовалось:

Привет Александр

Разберем подробнее строку:

parser.add_argument('name', nargs='?', default='мир!')

В ней мы с помощью метода add_argument и передаваемых ему параметров, задали необязательный (для этого указали nargs=’?’) позиционный аргумент. Если аргумент не передается, то он принимает значение указанное в default.

Важно помнить, что при позиционных аргументах важен их порядок в момент, когда мы вызываем скрипт. Первый аргумент, переданный скрипту, становится первым позиционным аргументом, второй аргумент — вторым позиционным аргументом и т.д.

Продолжим доработку кода. Теперь мы хотим, чтобы Имя передавалось именованным параметром —name

Для этого всего лишь надо изменить одну строку создания аргумента

parser.add_argument('--name', default='мир!')

Теперь можно запустить скрипт с именованным параметром —name:

python hello2.py --name Александр

Мы получим «Привет Александр», а при отсутствии параметра, будет выводится значение по умолчанию «Привет мир».

У названия параметра может быть краткая форма, она записывается с одним ««, например:

parser.add_argument('-n', '--name', default='мир!')

А что если в качестве параметра —name мы заходим передать Имя + Фамилия?

python hello2.py --name Александр Третьяков

Выполнив это сейчас мы получим ошибку error: unrecognized arguments: Третьяков поскольку модуль argparse решил что фамилия это отдельный аргумент.

Чтобы поправить ситуацию, используем дополнительный параметр метода add_argument — nargs со значением «+», который обозначает, что мы ожидаем одно или более значений аргумента.

Теперь повторно вызвав скрипт, получим все переданные параметры в виде списка:

Привет ['Александр', 'Третьяков']

Выбор агрументов из определенных вариантов

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

Если брать наш пример выше, можем добавить, чтобы скрипт принимал только определенные имена: Александр, Екатерина, Татьяна, Евгений. Для этого добавим в метод add_argument параметр choices, в котором укажем список возможных значений параметра (в нашем случае список имен).

parser.add_argument ('-n', '--name', choices=['Александр', 'Екатерина', 'Татьяна', 'Евгений'])

Теперь при вызове скрипта мы должны обязательно указать параметр —name со значением из этого списка иначе возникнет ошибка:

python hello2.py --name Екатерина

Получим:

Привет Екатерина

А если попробуем передать имя не из одобренного списка:

hello2.py --name Ольга

Получим ошибку:

usage: hello2.py [-h] [-n {Александр,Екатерина,Татьяна,Евгений}]

hello2.py: error: argument -n/--name: invalid choice: 'Ольга' (choose from 'Александр', 'Екатерина', 'Татьяна', 'Евгений')

Справка (помощь) по аргументам

Выше мы ограничили список возможных значений аргумента —name четырьмя именами, но как узнать об этом пользователю, который в первый раз использует скрипт, ему придаться вчитываться в текст ошибки, чтобы понять чего от него хочет программа. Как пользователю узнать о всех возможных аргументах, порядке их применения и их назначении?

Для этого мы можем оформить справку для программы, которая будет вызываться аргументом —help или -h. В справочной информации мы сможем указать название и версию программы, копирайт, описание того, что она делает, и список ожидаемых параметров.

Итак изменим 2 строчки нашего кода, добавив в него справочную информацию:

parser = argparse.ArgumentParser(
    prog='Greeting Script',
    description='Программа, которая говорит "Привет"',
    epilog='(c) Информация об авторе программы'

)

parser.add_argument ('-n', '--name', choices=['Александр', 'Екатерина', 'Татьяна', 'Евгений'], help='Список из имен, которые я могу приветствовать')

Теперь вызвав:

python hello2.py --help

Мы получим справку о нашей программе:

usage: Greeting Script [-h] [-n {Александр,Екатерина,Татьяна,Евгений}]

Программа, которая говорит "Привет"

optional arguments:
  -h, --help            show this help message and exit
  -n {Александр,Екатерина,Татьяна,Евгений}, --name {Александр,Екатерина,Татьяна,Евгений}
                        Список из имен, которые я могу приветствовать

(c) Информация об авторе программы

Аргументы как флаги

А что если мы хотим сделать так, чтобы при указании флага -bye программа говорила нам «До свидания»?

Для этого добавим строку:

parser.add_argument ('-bye', action='store_const', const=True, help='Установите, если нужно ли прощаться с пользователем')

В метод add_argument мы добавили 2 новых параметра. Первый — action, он предназначен для выполнения некоторых действий над значениями переданного аргумента. В нашем случае мы передали значение параметра action — store_const,  оно обозначает, что если данный аргумент (‘-bye’) указан, то он всегда будет принимать значение, указанное в другом параметре метода add_argument — const. А если аргумент передан не будет, то его значение будет равно None.

Так же в конце скрипта добавим вывод «До свидания», в случае установленного флага -bye:

if args.bye:
    print ('До свидания')

Теперь если добавить флаг -bye при вызове скрипта:

python hello2.py --name Александр -bye

Получим:

Привет Александр
До свидания

Без добавления -bye мы получим просто:

Привет Александр

Флаги со значениями True и False используются часто, поэтому для этих целей предусмотрено 2 специальных значения для параметра action: store_true и store_false.

Можно переписать наш код так:

parser.add_argument ('-bye', action='store_true', help='Установите, если нужно ли прощаться с пользователем')

Мы использовали store_true, т.е. если параметр ‘-bye’ передан, он примет значение True.

Кстати, выше мы увидели что для добавление второго, третьего и т.д. аргумента, нам нужно просто еще раз вызвать метод add_argument и передать ему значения параметра.

Окончательный код нашего файла hello2.py:

import argparse

parser = argparse.ArgumentParser(
    prog='Greeting Script',
    description='Программа, которая говорит "Привет"',
    epilog='(c) Информация об авторе программы'

)

parser.add_argument ('-n', '--name', choices=['Александр', 'Екатерина', 'Татьяна', 'Евгений'], help='Список из имен, которые я могу приветствовать')
parser.add_argument ('-bye', action='store_true', help='Установите, если нужно ли прощаться с пользователем')

args = parser.parse_args()

print(f'Привет {args.name}')

if args.bye:
    print ('До свидания')

На этом все, думаю общее представление о модуле argsparse вы получили, подробнее о нем можно почитать в  официальной документации https://docs.python.org/3/library/argparse.html.

Хостинг для ваших проектов