Как сделать консольное приложение python

Обновлено: 05.07.2024

Вместо сценариев оболочки, которые могут стать сложными и утомительными, мы можем использовать Python для автоматизации команд оболочки. В этом уроке мы узнаем, как запускать их ради масштабируемости и ремонтопригодности проектов Python.

Вступление

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

К счастью, мы можем использовать Python вместо shell-скриптов для автоматизации. Python предоставляет методы для выполнения команд оболочки, предоставляя нам ту же функциональность, что и скрипты этих оболочек. Изучение того, как выполнять команды оболочки на Python, открывает нам возможность автоматизировать компьютерные задачи структурированным и масштабируемым способом.

В этой статье мы рассмотрим различные способы выполнения команд оболочки в Python и идеальную ситуацию для использования каждого метода.

Использование os.system для выполнения команды

Python позволяет нам немедленно выполнить команду оболочки, которая хранится в строке, используя функцию os.system () .

Давайте начнем с создания нового файла Python под названием echo_adelle.py и введите следующее:

Первое, что мы делаем в нашем файле Python, – это импортируем модуль os , который содержит функцию system , которая может выполнять команды оболочки. Следующая строка делает именно это, запускает команду echo в нашей оболочке через Python.

В вашем терминале запустите этот файл с помощью следующей команды, и вы увидите соответствующий вывод:

Поскольку команды echo выводятся на наш stdout , os.system() также выводит вывод на наш stdout поток. Хотя команда os.system() не отображается в консоли, она возвращает код выхода команды оболочки. Код выхода 0 означает, что он работал без каких-либо проблем, а любое другое число означает ошибку.

Давайте создадим новый файл с именем cd_return_codes.py и введите следующее:

В этом скрипте мы создаем две переменные, которые хранят результат выполнения команд, изменяющих каталог на домашнюю папку, и на папку, которая не существует. Запустив этот файл, мы увидим:

Первая команда, которая изменяет каталог на домашний, выполняется успешно. Поэтому os.system() возвращает свой код выхода ноль, который хранится в home_dir . С другой стороны, unknown_dir хранит код выхода неудачной команды bash для изменения каталога на несуществующую папку.

Функция os.system() выполняет команду, выводит любой вывод команды на консоль и возвращает код выхода команды. Если мы хотим более тонкого управления вводом и выводом команды оболочки в Python, мы должны использовать модуль subprocess .

Выполнение команды с подпроцессом

Модуль subprocess – это рекомендуемый Python способ выполнения команд оболочки. Это дает нам гибкость подавлять вывод команд оболочки или цепочку входов и выходов различных команд вместе, в то же время обеспечивая аналогичный опыт os.system() для основных случаев использования.

В новом файле под названием list_subprocess.py , напишите следующий код:

Примечание: Как правило, вам нужно разделить аргументы на основе пробела, например ls-alh будет ["ls", "-alh"] , в то время как ls-a -l -h будет ["ls", "-a", - "l", "-h"] . В качестве другого примера echo hello world будет ["echo", "hello", "world"] , тогда как echo "hello world" или echo hello\ world будет ["echo", "hello world"] .

Запустите этот файл, и вывод вашей консоли будет похож на:

Стандартный вывод команды теперь передается на специальное устройство /dev/null , что означает, что вывод не будет отображаться на наших консолях. Выполните файл в вашей оболочке, чтобы увидеть следующие выходные данные:

Запуск этого файла приводит к следующим выводам:

Мы также можем вызвать Исключение без ручной проверки возвращаемого значения. В новом файле, false_subprocess.py , добавьте код ниже:

В вашем терминале запустите этот файл. Вы увидите следующую ошибку:

Используя check=True , мы говорим Python вызывать любые исключения, если возникает ошибка. Поскольку мы действительно столкнулись с ошибкой, оператор print в последней строке не был выполнен.

Запуск команды с помощью Popen

Подпроцесс .Класс Popen предоставляет разработчику больше возможностей при взаимодействии с оболочкой. Однако нам нужно быть более откровенными в отношении получения результатов и ошибок.

По умолчанию используется подпроцесс.Popen не останавливает обработку программы Python, если ее команда не закончила выполнение. В новом файле под названием list_popen.py , введите следующее:

Этот код эквивалентен коду list_subprocess.py . Он запускает команду с помощью подпроцесса .Popen и ждет его завершения , прежде чем выполнить остальную часть скрипта Python.

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

Метод poll() возвращает код выхода, если команда закончила выполнение, или None , если она все еще выполняется. Например, если бы мы хотели проверить, был ли list_dir завершен, а не ждать его, у нас была бы следующая строка кода:

Для управления вводом и выводом с помощью подпроцесса .Popen , нам нужно использовать метод communicate () .

В новом файле под названием cat_popen.py , добавьте следующий фрагмент кода:

Метод communicate() принимает аргумент input , который используется для передачи входных данных команде оболочки. Метод communicate также возвращает оба параметра stdout и stderr , когда они установлены.

Увидев основные идеи, лежащие в основе подпроцесса.Popen , теперь мы рассмотрели три способа запуска команд оболочки в Python. Давайте еще раз рассмотрим их характеристики, чтобы узнать, какой метод лучше всего подходит для требований проекта.

Какой из них я должен использовать?

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

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

Интерактивная консоль предоставляет доступ к истории команд, всем встроенным функциям и установленным модулям Python. Она позволяет использовать автозаполнение, исследовать возможности Python и вставлять код в файлы программирования после проверки.

Этот мануал научит вас работать с интерактивной консолью Python.

Доступ к интерактивной консоли

Доступ к интерактивной консоли Python можно получить с любого локального компьютера или сервера, на котором установлен Python.

Для входа в интерактивную консоль Python используйте команду:

Если вы настроили среду разработки, вы можете получить доступ к консоли внутри этой среды. Сначала запустите среду:

cd environments
my_env/bin/activate

Затем откройте консоль:

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

Python 3.5.2 (default, Nov 17 2016, 17:05:23)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

Поле для ввода следующей команды – три знака больше:

Вы можете указать определенную версию Python, добавив номер версии в команду без пробелов:

$ python2.7
Python 2.7.12 (default, Nov 19 2016, 06:48:10)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>

Вывод сообщает, что теперь будет использоваться версия Python 2.7.12. Если бы она была версией Python по умолчанию, открыть её интерактивную консоль можно было бы с помощью команды python2.

Чтобы вызвать интерактивную консоль версии Python 3 по умолчанию, нужно ввести:

$ python3
Python 3.5.2 (default, Nov 17 2016, 17:05:23)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

Также консоль этой версии можно вызвать с помощью команды:

Работа с интерактивной консолью Python

Интерактивный интерпретатор Python принимает синтаксис Python, который находится после префикса >>>.

Например, он позволяет присваивать значения переменным:

Вы можете присвоить значения нескольким переменным, чтобы обрабатывать математические операции.

>>> birth_year = 1868
>>> death_year = 1921
>>> age_at_death = death_year - birth_year
>>> print(age_at_death)
53
>>>

Как и в файле, в консоли можно задать значения переменных, выполнить математическую операцию и запросить результат.

Интерактивную консоль можно использовать как калькулятор.

Многострочный код Python в консоли

При создании многострочного кода в консоли интерпретатор Python использует троеточие (…) в качестве вспомогательной строки.

Чтобы выйти из вспомогательной строки, нужно дважды нажать Enter.

Чтобы понять, как это работает, рассмотрите этот код, который задает значения двум переменным и использует условное выражение, чтобы определить вывод.

>>> 8host = '8host'
>>> blog = 'blog'
>>> if len(8host) > len(blog):
. print('8host codes in Java.')
. else:
. print('8host codes in Python.')
.
8host codes in Java.
>>>

В данном случае первая строка длиннее, чем вторая, потому срабатывает первое условие и программа выводит соответствующую строку.

>>> if len(8host) > len(blog):
. print('8host codes in Java.')
File " ", line 2
print('8host codes in Java.')
^
IndentationError: expected an indented block
>>>

Импорт модулей

Интерпретатор Python позволяет быстро проверить, доступны ли те или иные модули в определенной среде программирования. Для этого существует оператор import:

>>> import matplotlib
Traceback (most recent call last):
File " ", line 1, in
ImportError: No module named 'matplotlib'

В данном случае библиотека matplotlib недоступна в текущей среде.

Чтобы установить эту библиотеку, используйте pip.

pip install matplotlib
Collecting matplotlib
Downloading matplotlib-2.0.2-cp35-cp35m-manylinux1_x86_64.whl (14.6MB)
.
Installing collected packages: pyparsing, cycler, python-dateutil, numpy, pytz, matplotlib
Successfully installed cycler-0.10.0 matplotlib-2.0.2 numpy-1.13.0 pyparsing-2.2.0 python-dateutil-2.6.0 pytz-2017.2

Установив модуль matplotlib и его зависимости, вы можете вернуться в интерактивный интерпретатор.

(my_env) 8host@ubuntu:~/environments$ python
>>>import matplotlib
>>>

Теперь вы можете использовать импортированный модуль в этой среде.

Выход из интерактивной консоли Python

Закрыть консоль Python можно двумя способами: с помощью клавиатуры или с помощью функции Python.

Чтобы закрыть консоль, можно нажать на клавиатуре Ctrl + D в *nix-подобных системах или Ctrl + Z + Ctrl в Windows.

>>> age_at_death = death_year - birth_year
gt;>> print(age_at_death)
53
>>>
8host@ubuntu:~/environments$

Также в Python есть функция quit(), которая закрывает консоль и возвращает вас в стандартный терминал.

>>> octopus = 'Ollie'
>>> quit()
8host@PythonUbuntu:~/environments$

Функция quit() записывается в историю, а комбинации клавиш – нет. Это следует учитывать при выходе из консоли. Откройте файл истории /home/8host /.python_history

.
age_at_death = death_year - birth_year
print(age_at_death)
octopus = 'Ollie'
quit()

История консоли Python

Еще одним преимуществом интерактивной консоли Python является история. Все команды регистрируются в файле .python_history (в *nix-подобных системах).

На данный момент файл истории Python выглядит так:

import pygame
quit()
if 10 > 5:
print("hello, world")
else:
print("nope")
8host = '8host'
blog = 'blog'
.

Чтобы закрыть файл, нажмите Ctrl + X.

Отслеживая историю, вы можете вернуться к предыдущим командам, скопировать, вставить или изменить этот код, а затем использовать его в файлах программы или Jupyter Notebook.

Заключение

Интерактивная консоль Python предоставляет пространство для экспериментов с кодом Python. Вы можете использовать ее как инструмент для тестирования, разработки логики программы и многого другого.

Для отладки файлов программы Python вы можете использовать модуль code и открыть интерактивный интерпретатор внутри файла.

Все мы, специалисты по анализу данных, выполняем множество рутинных и повторяющихся действий. Сюда относятся: создание еженедельных отчетов, ETL -операции (извлечение, преобразование, загрузка), обучение моделей с помощью различных наборов данных и т.д. Зачастую на выходе у нас появляется множество Python-скриптов, и каждый раз при выполнении кода нам приходится менять его параметры. Лично меня это бесит! Именно поэтому я стал превращать скрипты в повторно используемые инструменты интерфейса командной строки (CLI-инструменты). Это повысило эффективность и продуктивность моей каждодневной работы. Начинал я с Argparse , но не особо проникся им, поскольку приходилось писать множество убогого кода. И тут я подумал: неужели нельзя достичь тех же результатов без постоянного переписывания кода? Да и вообще, смогу ли я когда-нибудь получать удовольствие от создания CLI-инструментов?

Click — это ваш друг и соратник!

Так что же такое Click? Из официальной документации следует:

Click призван сделать процесс написания инструментов командной строки быстрым и увлекательным, избавляя при этом от всякого рода разочарований из-за невозможности реализации желаемого CLI API.

Звучит шикарно! Как считаете?

В данной статье я поделюсь с вами практическим руководством по пошаговому созданию Python CLI с помощью Click на Python и продемонстрирую вам базовые опции и преимущества этой библиотеки. Выполнив данный пример, вы научитесь писать CLI-инструменты быстро и безболезненно 🙂 Давайте уже займемся делом!

Обучающий урок

В ходе данного урока мы будем пошагово создавать CLI с помощью Click на Python. Я начну с самых основ и в каждом шаге буду рассказывать про концепцию, предлагаемую Click. Дополнительно мне понадобится Poetry для управления пакетами и зависимостями.

Подготовка

Для начала давайте установим Poetry. Существует множество способов установки, однако здесь мы воспользуемся pip:

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

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

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

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

smiley

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

hello2.py --name Ольга

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

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

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

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

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

python hello2.py --help

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

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

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

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

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

Теперь если добавить флаг -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 и передать ему значения параметра.

Читайте также: