Python: модуль argparse
Содержание:
- Зачем нужен модуль argparse?
- Зачем вам писать скрипты и инструменты для командной строки на Python?
- Опциональные параметры
- Подробности об argparse
- Exception getopt.GetoptError
- По ту сторону Jupyter Notebook
- Работа с файлами
- Более реалистичный пример CLI с click
- Переключатель функций
- Основы интерфейса командной строки
- Python 3 курс
- Работа со строками.
- Добавляем автоматически генерируемые инструкции по использованию
- Optional arguments
- Более реалистичный пример CLI на Python с использованием click
- *args и **kwargs в вызовах функций
Зачем нужен модуль argparse?
Модуль argparse позволяет разбирать аргументы, передаваемые скрипту при его запуске из командной строки, и даёт возможность пользоваться этими аргументами в скрипте. То есть речь идёт о том, что этот модуль позволяет предоставлять скрипту некие данные в момент его запуска, а этими данными скрипт сможет воспользоваться во время выполнения его кода. Модуль argparse — это средство, с помощью которого можно наладить общение между автором программы и тем, кто ей пользуется, например — между вами, когда вы сегодня пишете скрипт, и вами же, когда вы завтра его запускаете, что-то ему передавая.
Использование argparse означает, что, при необходимости изменить поведение скрипта или при необходимости передачи ему неких данных, если это предусмотрено автором скрипта, пользователю не нужно редактировать программный код. В результате скрипты обретают определённый уровень гибкости.
Зачем вам писать скрипты и инструменты для командной строки на Python?
Код выше – всего лишь пример, не очень полезный в реальной жизни. На самом деле скрипты бывают куда более сложные
Возможно, вы имели опыт с ними и знаете, что они могут быть важной частью нашей повседневной работы: некоторые скрипты остаются на протяжении всего времени жизни проекта, для которого они были написаны. Некоторые начинают приносить пользу другим командам или проектам
У них даже может расширяться функционал.
В этих случаях важно сделать скрипты более гибкими и настраиваемыми с помощью параметров командной строки. Они позволяют указать имя сервера, учётные данные или любую другую информацию скрипту
Здесь приходят на выручку такие модули, как optparse и argparse, которые делают нашу жизнь на порядок проще. Но прежде чем мы с ними познакомимся, давайте разберёмся с терминологией.
Опциональные параметры
Вернёмся к нашей программе для преобразования видео в картинки. Что произойдёт при попытке выполнить команду ?
Вы получите справочную информацию о вашем скрипте, чтобы вы знали, что делать.
Результат выполнения команды python videos.py — help
Отлично! — пример опционального параметра. Заметьте, что это — единственный параметр, который получаете сразу, но вы можете собственноручно создать и другие.
Создаются они практически так же, как и позиционные, за исключением того, что в начале названия у них (или и один дополнительный символ для укороченной версии). Например, создадим опциональный параметр так:
В следующем примере показано создание и обращение к опциональным параметрам. Заметьте, что в этом случае мы устанавливаем как тип данных. Разрешается использовать любой другой тип данных, поддерживаемый Python.
Заметьте, что аргумент, определённый как , становится переменной пространства имён без знаков тире: .
Также заметьте, что для опциональных параметров можно задавать значения по умолчанию. В этом примере результатом выполнения команды будет 2.
Опциональные аргументы могут быть заданы непосредственно во время вызова программы через командную строку таким образом: . В таком случае программа выведет 3.
Целые числа
Это далеко не все возможности . Например, ещё можно соединять аргументы в списки при помощи . Также можно задавать ограничения значения при помощи . Для того чтобы узнать больше об этом модуле, ознакомьтесь с документацией.
Где ещё использовать argparse?
Также можно использовать при работе с программами в контейнере Docker. Если вы хотите отправить скрипту данные во время сборки, сделайте это при помощи RUN. Если же хотите передать входные данные в программу непосредственно во время её работы, используйте CMD или ENTRYPOINT.
Подробности об argparse
Только что мы рассмотрели простой пример работы с argparse. Теперь давайте обсудим некоторые подробности, касающиеся argparse.
▍Позиционные аргументы
Конструкция вида
из скрипта
предназначена для создания позиционного аргумента (positional argument). При вызове скрипта важен порядок указания таких аргументов. Так, первый аргумент, переданный скрипту, становится первым позиционным аргументом, второй аргумент — вторым позиционным аргументом.
Что произойдёт в том случае, если скрипт запустить вообще без аргументов, выполнив в терминале команду
В таком случае будет выведено сообщение об ошибке следующего вида:
В результате оказывается, что для того, чтобы запустить скрипт, в котором предусмотрено использование позиционных аргументов, такие аргументы всегда нужно указывать при его запуске.
▍Необязательные аргументы
Что произойдёт при запуске нашего скрипта командой
В ответ будет выведена справочная информация о нём. Это — именно те сведения о позиционных аргументах, которые мы указывали при описании соответствующих переменных:
Скрипт сообщил нам много интересного о том, чего он ждёт от пользователя, а
— это пример необязательного аргумента (optional argument)
Обратите внимание на то, что. (или
(или
) — это единственный стандартный необязательный аргумент, которым мы можем пользоваться при работе с argparse, но, если вам нужны и другие необязательные аргументы, их можно создавать и самостоятельно.
Необязательные аргументы создают так же, как и позиционные. Основная разница между командами их создания заключается в том, что при указании имён таких аргументов эти имена начинаются с последовательности символов
, или, для кратких форм аргументов, с символа
. Например, необязательный аргумент можно создать так:
Вот пример того, как создавать и использовать необязательные аргументы
Обратите внимание на то, что мы, описывая здесь необязательный аргумент, указали его тип как. То есть он представляет собой целое число
В подобной ситуации можно использовать и другие типы Python
. То есть он представляет собой целое число. В подобной ситуации можно использовать и другие типы Python.
Аргумент, описанный как
, доступен в программе в виде свойства объекта
с именем
Необязательным аргументам можно назначать значения, которые они будут иметь по умолчанию. В нашем случае, если при вызове скрипта аргументу
не будет задано никакого значения, в него будет записано число 2, которое и будет выведено в консоль. Для того чтобы задать значение этого аргумента во время запуска скрипта можно воспользоваться такой конструкцией:
Exception getopt.GetoptError
This is raised when an unrecognized option is found in the argument list or when an option requiring an argument is given none.
The argument to the exception is a string indicating the cause of the error. The attributes msg and opt give the error message and related option.
Example
Consider we want to pass two file names through command line and we also want to give an option to check the usage of the script. Usage of the script is as follows −
usage: test.py -i <inputfile> -o <outputfile>
Here is the following script to test.py −
#!/usr/bin/python import sys, getopt def main(argv): inputfile = '' outputfile = '' try: opts, args = getopt.getopt(argv,"hi:o:",) except getopt.GetoptError: print 'test.py -i <inputfile> -o <outputfile>' sys.exit(2) for opt, arg in opts: if opt == '-h': print 'test.py -i <inputfile> -o <outputfile>' sys.exit() elif opt in ("-i", "--ifile"): inputfile = arg elif opt in ("-o", "--ofile"): outputfile = arg print 'Input file is "', inputfile print 'Output file is "', outputfile if __name__ == "__main__": main(sys.argv)
Now, run above script as follows −
$ test.py -h usage: test.py -i <inputfile> -o <outputfile> $ test.py -i BMP -o usage: test.py -i <inputfile> -o <outputfile> $ test.py -i inputfile Input file is " inputfile Output file is "
python_basic_syntax.htm
Previous Page
Print Page
Next Page
По ту сторону Jupyter Notebook
Когда я впервые увидел , первой мыслью было: “Что это за чёрная магия?”. Казалось, что переключиться на Jupyter Notebook — гораздо более лёгкое решение. Как оказалось позже, это решение было полукомпромиссным.
Я хотел запускать всю программу целиком, а не каждую ячейку блокнота по отдельности. Скрипт с использованием был бы гораздо более удобным в использовании и менее трудоёмким. К сожалению, я слишком торопился и не смог найти документацию, которая позволила бы разобраться с модулем.
С этого момента прошло достаточно много времени, я узнал больше об . Он незаменим!
Вот то, что вам нужно знать.
Работа с файлами
Для начала, маленькое предисловие. В питоне (как и в подавляющем большинстве языков программирования) с файлами можно делать много разных операций: читать его построчно, читать его целиком, писать в него, двигать по нему курсор позиции, с которой мы будем читать или в которую мы будем писать…
Открытие файла.
В питоне каждый файл, с которым мы работаем, обозначается объектом. (А объект обозначается переменной).
Соответственно, прежде, чем с файлом начинать работать, нам нужно создать питонское представление об этом файле – создать объект, который представляет именно конкретный файл. В питоне эта операция называется «открыть файл». Делается это так:
file = open('file.txt')
Такой файл можно только читать. Питон будет запрещать для него операции записи. Если нам нужно в файл писать, то мы пишем так:
file = open('file.txt', "w")
Тут сразу предупреждаю: в тот момент, когда питон открывает файл на запись, если такой файл уже существовал, то он будет стёрт! Это свойство даже не столько питона, сколько большинства операционных систем. Его нужно всегда учитывать: нельзя указывать одинаковым входной и выходной файл для программы.
Что делать, если мы хотим дописать в файл? Для этого существуют еще один параметр ‘a’ (от ‘append’):
file = open('file.txt', "a")
Путь к файлу указывается либо относительно текущей директории, либо относительно корневой директории (абсолютный путь):
open("hello.txt") # открыть файл hello.txt в текущей директории # UNIX only: open("../task2/README") # открыть файл README, директорией выше в директории task2 open("_darcs/prefs/author") # открыть файл author в поддиректории prefs в директории _darcs open("/bin/ls") # открыть файл ls в директории bin, лежащей в корневой директории / # Windows only: open("..\\Task2\\README") open("_darcs\\prefs\\author") open("H:\\Task3\\Python\\ls.py")
Так эти строки будут выглядять изнутри питона. Если имена файлов приходят из аргументов командной строки, то дублировать бэкслеши не надо. (В командной строке будет H:\Task3\Python – то, как FAR пишет пути, если ему щёлкнуть Ctrl-Enter по файлу).
Чтение по строкам
Если мы подставляем файл туда, где питон ожидал бы список, то питон будет интерпретировать файл как список строк файла – включая переносы в концах строк.
for line in file: print line
Если мы распечатаем каждую строку таким образом, то в итоге на экране мы увидим все строки через пробел (пустую строку). Это произойдет из-за того, что в файле в конце каждой строки стоит символ ‘\n’, а print автоматически прибавляет этот символ к концу печатаемого объекта. О решении этой проблемы поговорим чуть позже (см. Работа со строками и всякие полезные вещи при работе с файлами).
Чтение по байтам.
bytes=file.read(1)
метод .read(1) возвращает строку bytes, в которой будет находиться 1 байт, прочитанный из файла.
Чтение целиком
Самым удобным способом чтения файла является его запись в 1 строку целиком с помощью метода .read():
contents=file.read()
Запись в файл.
file.write("Hello, file!\n")
дописывает одну строку в конец файла.
Обратите внимания: в отличие от print, эта функция переноса строки в конец не дописывает, нам приходится вставлять его туда самостоятельно!
StdIO
Существует три специальных потока, которые называются: стандартный поток ввода, стандартный поток вывода и стандартный поток ошибок.
Можно рассматривать каждую программу как некий универсальный переработчик, который имеет два разъёма: вход и выход. Эти вход и выход называются «стандартный вход» (stdin) и «стандартный выход» (stdout). Если мы у програмы никуда не привязываем выход, то, что из неё высыпается, сыпется на экран. А если не привязан вход, то она присасывается к клавиатуре и ловит всё, что вы набираете в консоли.
С точки зрения питона:
Стандартный вывод – это то, куда пишет print. Это такой файл. К нему можно дотянуться через sys.stdout.
Стандартный ввод – это то, чем мы пока что не пользовались. Это тоже такой файл. К нему можно дотянуться, как вы догадались, черзе sys.stdin.
Про стандартный поток ошибок — sys.stderr, это в общем то же самое, что stdout, только в него пишутся ошибки, а не содержательная выдача программы.
Более реалистичный пример CLI с click
Теперь, когда известно, как click упрощает создание простого CLI, рассмотрим более реалистичный пример. Напишем программу, которая позволяет взаимодействовать с веб API. Сегодня многие используются ими, потому что они предоставляют доступ к некоторым любопытным данным.
API который будет рассматриваться для оставшейся части этого материала – это OpenWeatherMap API. Он сообщает текущую погоду, а также прогноз на пять дней для определенного местоположения. Начнем с шаблона API, возвращающего текущую погоду для местоположения.
Одним из инструментов, который позволяет исследовать новый API, является программа HTTPie, которую можно использовать для вызова API ресурса и просмотра возвращаемого результата.
Давайте посмотрим, что произойдет, когда будет вызван API для города Москва:
Важным наблюдением из приведенного выше примера является то, что для получения текущей погоды определяется два параметра запроса (обозначаемые == при использовании HTTPie) :
- q – местонахождение
- appid — это ключ к API
Также можно создать простую реализацию с использованием Python и библиотеки Requests (будем игнорировать обработку ошибок и неудачные запросы для простоты.)
Функция создаёт простой запрос к API погоды, используя два параметра запроса. Она принимает обязательный аргумент location, который является строкой. Также можно предоставить ключ API, передав api_key в вызове функции. Он является необязательным и используется для примера по умолчанию.
Результат работы программы для Москвы
Переключатель функций
Допустим, нам захотелось не просто хранить результат в локальном , но и загружать его на сервер. Кроме того, есть не только целевой сервер, но и сервера для разработки, тестирования и реальной базы. И ко всем им нужно обращаться по разным . Один из способов выбора сервера — это передача полного — адреса как аргумента, который пользователь должен будет прописать. Причем, этот способ не просто рискованный в плане ошибок, но и весьма кропотлив. Поэтому для облегчения жизни пользователей я использую переключатели функций. Принцип их работы лучше всего иллюстрирует код ниже:
...@click.option("--dev", "server_url", help="Загрузить на сервер разработки",flag_value='https://dev.server.org/api/v2/upload',)@click.option("--test", "server_url", help="Загрузить на тестовый сервер",flag_value='https://test.server.com/api/v2/upload',)@click.option("--prod", "server_url", help="Загрузить на основной сервер",flag_value='https://real.server.com/api/v2/upload',default=True)def process(in_file, out_file, verbose, server_url): """ Обработка входного файла IN и хранение результата в выходном файле OUT. """ print_func = print if verbose else identity print_func("Мы начнем с входного значения") input = read_csv(in_file) print_func("Затем обработаем данные") output = process_csv(input) print_func("И, наконец, выдадим готовый файл") write_excel(output, out_file) print_func("Загрузим его на сервер") upload_to(server_url, output)...
Здесь я добавил три декоратора для трех возможных -адресов серверов. Важный момент: все три опции содержат одну общую переменную . В зависимости от выбранной опции значение соответствует значению, определенному в . Их вы выбираете, добавляя в качестве аргумента , или . Таким образом, при выполнении:
python -m cli_tutorial.cli -i path/to/some/file.csv --test
соответствует . Если оставить флажки пустыми, то возьмет значение , поскольку я прописал .
Основы интерфейса командной строки
Интерфейс командной строки (CLI) начинается с имени исполняемого файла. Вы вводите имя в консоль и получаете доступ к главной точке входа скрипта, такого как pip.
В зависимости от сложности CLI обычно есть определённые параметры, которые вы можете передавать скрипту:
- Аргумент, который является обязательным параметром. Если его не передать, то CLI вернёт ошибку. Например, в следующей команде click является аргументом: .
- Опция – необязательный параметр, который объединяет имя и значение, например . Вы говорите CLI, что значение должно использоваться как директория для кэша.
- Флаг, который включает или выключает определённый сценарий. Вероятно, самым частым является . Вы только указываете имя, а CLI самостоятельно интерпретирует значение.
С более сложными CLI, такими как pip или Heroku CLI, вы получаете доступ к набору функций, которые собраны под главной точкой входа. Они обычно называются командами или подкомандами.
Возможно, вы уже использовали CLI, когда устанавливали Python-библиотеку с помощью команды . Команда говорит CLI, что вы хотите использовать функцию установки пакета, и даёт вам доступ к параметрам, характерным для этой функции.
Python 3 курс
Python3 курсPython3 Базовая грамматикаPython3 Основные типы данныхPython3 переводчикPython3 примечаниеPython3 операторыPython3 цифровойPython3 строкаPython3 списокPython3 КортежPython3 словарьPython3 Первый шаг в программированииPython3 условия контроляPython3 LoopsPython3 Итераторы и генераторыPython3 функцияPython3 структура данныхPython3 модульPython3 Ввод и выводPython3 FilePython3 OSPython3 Ошибки и исключенияPython3 Объектно-ориентированныйPython3 Стандартная библиотека ОбзорPython3 примеровPython3 Регулярные выраженияPython3 CGIпрограммаPython3 MySQLPython3 Сетевое программированиеPython3 SMTPОтправить по электронной почтеPython3 МногопоточностьPython3 XMLрешениеPython3 JSONPython3 Дата и время
Работа со строками.
Итак, вернемся к чтению по строкам.
for line in file: print line
Как уже было сказано, у нас возникает проблема с удвоением ‘\n’. Избавиться от этого лишнего пробельного символа можно с помощью метода strip().
.strip(): обрезание символов с концов строки
strip отрезает с начала и конца строки те символы, которые указаны в его аргументах (т.е. в скобках). Пустые скобки означают пробельные символы
>>> a="\t 1 2 " >>> a.strip() '1 2'
Важно! Строки, как и кортежи, нельзя изменить, поэтому при их любой обработке каким-то методом будет возвращаться новая строка!
То есть:
>>> a="\t 1 2 " >>> a.strip() '1 2' >>> a "\t 1 2 "
Если мы напишем:
>>> a=a.strip()
то a изменит адрес, однако исходная строка останется прежней.
Еще примеры со strip:
>>> '123abc231'.strip('12') '3abc23'
Как уже было сказано, strip обрезает с начала и конца строки все символы, которые указаны в его аргументах. Он работает только посимвольно! Поэтому с его помощью нельзя вырезать из строки ‘123abc231’число 12.
Вернемся к нашей проблеме. Метод strip() можно использовать, однако он удалит еще пробелы и в начале, что уже не есть хорошо. Чтобы избежать этого, надо указать в аргументах символ ‘\n’, который обычно присутствует только в конце. Для полной уверенности можно использовать разновидность метода strip — rstrip, который вырезает символы с правого конца (аналогично, существует метод lstrip для левого). Тогда:
for line in file: print line.rstrip('\n')
.split(): разбиение строки по заданным разделителям
Разбить строку на элементы списка можно с помощью метода .split()
>>> "\t 1 2 ".split()
В данном случае split() возвращает список, элементами которого являются слова, разделенные в исходной строке пробельными символами.
Ниже в примере _ означает пробел!
>>> '1,_2,_3,4,_5'.split(',_') # в аргументе split указываем разделитель на элементы >>> a='1,_2,_3,4,_5'.split(',')
split(«строка») разбивает по строке, а не по символам, из которых она состоит!
split() при разбиении выкидывает пробелы в начале и в конце строки (смотри пример выше), а split(» «) нет!
>>> "\t 1 2 ".split('')
Есть два разделителя подряд – будет в списке пустая строка.
split(x,y): x — разделитель, y — вернуть первые y разбиений.
>>> ',,1,2,,3'.split(',',2) >>> '1'.split(',',2)
.find(): поиск подстроки в строке
find(substring])
Возвращает индекс первого вхождения подстроки в строку:
>>> 'I like limes'.find('li') 2
Можно также искать только в заданной подстроке исходной строки:
>>> 'I like limes'.find('li',4) 7
Если ничего не нашлось, возвращается -1:
>>> 'I like limes'.find('li',4,7) -1 startswith (prefix])
Возвращает True, если строка начинается с данной подстроки:
>>> 'I like limes'.startswith('I like') True
Так же, как и с find(), можно ограничивать подстроку в исходной строке:
>>> 'I like limes'.startswith('like',2) True
Добавляем автоматически генерируемые инструкции по использованию
Можете себя похвалить, вы создали отличный небольшой CLI почти без шаблонного кода. Однако прежде чем вы решите отдохнуть, давайте убедимся, что новый пользователь будет знать, как пользоваться нашим CLI, путём добавления документации. Не бойтесь, всё будет просто.
Сначала давайте проверим, что выведет флаг после всех сделанных изменений. Довольно неплохо, учитывая что мы не приложили к этому никаких усилий:
Первое, что нужно исправить, это добавить описание для нашей опции с API-ключом. Всё, что нам для этого нужно сделать, – добавить справочный текст в декоратор :
Второе (и последнее), что мы сделаем, — добавим документацию для всей click-команды. Самый простой и самый питонический способ сделать это — добавить строку документации в нашу функцию . Да, нам в любом случае нужно сделать это, поэтому это не лишняя работа:
Сложив всё вместе, мы получаем хороший вывод для нашего инструмента:
Optional arguments
In our “ls” example above, we made use of the optional argument “-l” to get more information about a file. The program below will display something when –verbosity is specified and display nothing when not.
An optional argument (or option) is (by default) given None as a value when its not being used. Using the –verbosity option, only two values are actually useful, True or False.
The keyword “action” is being given the value “store_true” which means that if the option is specifed, then assign the value “True” to args.verbose Not specifying the option implies False.
If we run the program with the –help option, we can see:
Run the program using the –verbose option
Более реалистичный пример CLI на Python с использованием click
Теперь, когда вы знаете, как click упрощает написание CLI, давайте взглянем на более реалистичный пример. Мы напишем программу, которая позволяет нам взаимодействовать с веб-API.
API, который мы дальше будем использовать, — OpenWeatherMap API. Он предоставляет информацию о текущей погоде, а также прогноз на пять дней для определённого местоположения. Мы начнём с тестового API, который возвращает текущую погоду для места.
Прежде чем мы начнём писать код, давайте познакомимся с API. Для этого можно использовать сервис HTTPie, включая онлайн-терминал.
Давайте посмотрим, что случится, когда мы обратимся к API с Лондоном в качестве местоположения:
Если вы смущены наличием API-ключа в примере сверху, не переживайте, это тестовый API-ключ, предоставляемый сервисом.
Более важное наблюдение заключается в том, что мы отправляем два параметра (обозначаемые при использовании HTTPie), чтобы узнать текущую погоду:
- — место, в котором мы хотим узнать погоду;
- — наш API-ключ.
Это позволяет нам создать простую реализацию на Python с использованием библиотеки requests (опустим обработку ошибок и неудачных запросов для простоты):
Эта функция делает простой запрос к API, используя два параметра. В качестве обязательного аргумента она принимает (местоположение), которое должно быть строкой. Также мы можем указать API-ключ, передавая параметр при вызове функции. Это необязательно, так как по умолчанию используется тестовый ключ.
И вот мы видим текущую погоду в Python REPL:
*args и **kwargs в вызовах функций
*args и **kwargs можно использовать для передачи аргументов в функцию.
Создайте файл some_args.py. Рассмотрим такой код (поместите его в новый файл):
В функции есть три параметра: arg_1, arg_2 и arg_3. Функция выведет каждый из этих аргументов. Затем мы создаем переменную, которой присваивается итерируемый тип (в данном случае кортеж). Эту переменную можно передать в функцию с помощью звездочки.
Запустите программу:
Также можно изменить эту программу и заменить кортеж другим итерируем типом (например, списком). Также нужно объединить * args с именованным параметром:
Запустите программу. Вывод:
Аргументы с ключевым словом ** kwargs могут использоваться для вызова функции аналогичным образом. В файле some_kwargs.py создайте переменную, присвойте ей словарь с тремя парами «ключ-значение» (здесь используется kwargs, но его можно вызывать как угодно) и передайте её функции с тремя аргументами:
Запустите программу: