52

Интересный Python #10: CLI-приложения

CLI-приложение (Command Line Interface) - это такое приложение, в котором все действия осуществляются с помощью командной строки, в которую вводятся команды и параметры.

Интересный Python #10: CLI-приложения Программирование, Python, IT, Обучение, Длиннопост

Пример для Windows:

1. Откройте командную строку. Для этого нажмите Win + R, в открывшемся окне напишите cmd и от души приложитесь по кнопке Enter;

2. Введите команду tasklist и нажмите Enter. Вы увидите список запущенных процессов, их идентификаторы и объём памяти, которые они занимают;

3. Выполните команду tasklist /fi "memusage gt 200000", то есть добавьте к tasklist параметр /fi "memusage gt 200000". Вы увидите список процессов, занимающих в памяти более 200 000 килобайт.


Ну а если вы уже знакомы с Git, Docker и другими инструментами, то с их CLI вы наверняка имели дело.


С помощью библиотеки click вы легко сможете создавать свои CLI-приложения. В конце поста, как и всегда, будет тренировочное задание. Приятного чтения :)

Как установить click

1. Откройте терминал (командную строку);

2. Если умеете пользоваться виртуальным окружением, то создайте и активируйте его. Если нет, то пропустите этот шаг;

3. Выполните команду pip install click.

Документация

У click очень подробная и качественная документация. Ознакомиться с ней можно здесь.

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

Интересный Python #10: CLI-приложения Программирование, Python, IT, Обучение, Длиннопост
Интересный Python #10: CLI-приложения Программирование, Python, IT, Обучение, Длиннопост
Дальше будет много примеров кода. На Пикабу они выкладываются в виде скриншотов. Забрать их в виде текста можно здесь.

Вот так выглядит простейшее консольное приложение на click:

Интересный Python #10: CLI-приложения Программирование, Python, IT, Обучение, Длиннопост

Запустите командную строку и выберите ту директорию, в которой содержится ваш скрипт с расширением .py. Сменить директорию можно с помощью команды cd.

Интересный Python #10: CLI-приложения Программирование, Python, IT, Обучение, Длиннопост

Выполните несколько раз команду python main.py. Вместо main.py должно быть имя вашего скрипта. Каждый раз вы увидите в консоли новое случайное число.

Интересный Python #10: CLI-приложения Программирование, Python, IT, Обучение, Длиннопост
Интересный Python #10: CLI-приложения Программирование, Python, IT, Обучение, Длиннопост
Интересный Python #10: CLI-приложения Программирование, Python, IT, Обучение, Длиннопост

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


Опции - это необязательные параметры, которые могут идти в любом порядке. Передаются по имени, выглядят как --option-name [value].


Общий вид: command [options] <arguments>. То есть сначала передаются все опции, потом все аргументы.


Аргументы и опции добавляются к команде с помощью декораторов @click.argument и @click.option.

Интересный Python #10: CLI-приложения Программирование, Python, IT, Обучение, Длиннопост

Теперь использовать скрипт можно так:

Интересный Python #10: CLI-приложения Программирование, Python, IT, Обучение, Длиннопост
Интересный Python #10: CLI-приложения Программирование, Python, IT, Обучение, Длиннопост
Интересный Python #10: CLI-приложения Программирование, Python, IT, Обучение, Длиннопост

Отдельный вид опций - это флаги. Для них не нужно указывать никакого конкретного значения, они либо есть, либо их нет. Во многих консольных приложениях используется флаг --verbose («многословный»). Давайте сделаем так, чтобы при наличии такого флага в консоль выводилось не только число, но и небольшое сообщение.

Интересный Python #10: CLI-приложения Программирование, Python, IT, Обучение, Длиннопост

Теперь использовать скрипт можно так:

Интересный Python #10: CLI-приложения Программирование, Python, IT, Обучение, Длиннопост
Интересный Python #10: CLI-приложения Программирование, Python, IT, Обучение, Длиннопост
Интересный Python #10: CLI-приложения Программирование, Python, IT, Обучение, Длиннопост

click автоматически добавляет команду --help, которая выводит в консоль справочную информацию по командам, зарегистрированным с помощью @click.command. Попробуйте выполнить ваш скрипт с флагом --help, и вы увидите следующее:

Интересный Python #10: CLI-приложения Программирование, Python, IT, Обучение, Длиннопост

При регистрации опции можно передать аргумент help, в котором будет содержаться справочная информация об этой опции.

Для аргументов справочную информацию указывать нельзя.

Интересный Python #10: CLI-приложения Программирование, Python, IT, Обучение, Длиннопост
Интересный Python #10: CLI-приложения Программирование, Python, IT, Обучение, Длиннопост

Напишите CLI-приложение, которое будет принимать в качестве аргумента строку и подсчитывать количество уникальных букв в нём.

Например, для строки 'Мама мыла раму' приложение выведет следующий результат:

Интересный Python #10: CLI-приложения Программирование, Python, IT, Обучение, Длиннопост

Если передан флаг --ignore-case (игнорировать регистр символов), то результат должен быть таким:

Интересный Python #10: CLI-приложения Программирование, Python, IT, Обучение, Длиннопост

А если ещё и передан флаг --sort, то таким:

Интересный Python #10: CLI-приложения Программирование, Python, IT, Обучение, Длиннопост

Обратная связь

Как и всегда, буду рад видеть ваши решения в комментариях. По каждому из них будет предоставлена обратная связь от наших код-ревьюеров.


Код нужно обязательно представить в 2 форматах:

- изображение, сгенерированное на https://carbon.now.sh/;

- ссылка на код, сгенерированная через codepile.net или аналогичный сервис.

Программирование на python

885 постов11.9K подписчиков

Правила сообщества

Публиковать могут пользователи с любым рейтингом. Однако!


Приветствуется:

• уважение к читателям и авторам

• конструктивность комментариев

• простота и информативность повествования

• тег python2 или python3, если актуально

• код публиковать в виде цитаты, либо ссылкой на специализированный сайт


Не рекомендуется:

• допускать оскорбления и провокации

• распространять вредоносное ПО

• просить решить вашу полноценную задачу за вас

• нарушать правила Пикабу

3
Автор поста оценил этот комментарий

@SupportTech, добрый день! Можно ли как-то добавить отступы между изображениями? Сейчас они приклеиваются друг к другу, и приходится "лайфхачить", вставляя небольшие белые изображения-заглушки (см. пост). Но на тёмной теме это, естественно, работает не так, как хотелось бы.


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

показать ответы
0
Автор поста оценил этот комментарий

А есть ли для Python явная типизация в каком-то виде по аналогии с TypeScript? Потому что долго мозги себе долбал когда приходилось парсить выводы нейросетей с многомерными массивами, а по коду фиг поймёшь где какие размеры получаются после numpy преобразований.

раскрыть ветку (1)
1
DELETED
Автор поста оценил этот комментарий

Это была моя первая мысль ещё при написании первого варианта, но разве set(string) не сломает порядок букв в словаре?

раскрыть ветку (1)
1
Автор поста оценил этот комментарий

А, ну в принципе логично, не подумал про это. Не всегда же флаг sort устанавливается. Тогда...

Иллюстрация к комментарию
1
DELETED
Автор поста оценил этот комментарий

Да, разница огромная.

В этом и есть моя проблема - мой код никто не читает!


Мой первый код работал правильно, но не был оптимизирован. Без вашей вычитки я бы так его и оставил, довольный тем, что он работает).

раскрыть ветку (1)
1
Автор поста оценил этот комментарий

Ну штош, рад, что помог :)

1
DELETED
Автор поста оценил этот комментарий

Был уверен, что "Counter" ломает порядок расположения знаков относительно введенной строки. Оказывается, что нет, и эту функцию можно использовать. Удалил лишнюю функцию, так как Counter её заменяет полностью, и объявлять дополнительную функцию чтобы включить Counter и потом вызывать её в принципе не имеет смысла.


Спасибо за разбор кода!


Попытка номер 3.

Код: https://www.codepile.net/pile/Mj2v6xjR

Иллюстрация к комментарию
раскрыть ветку (1)
1
Автор поста оценил этот комментарий

В принципе, можно было и без Counter обойтись, там 1 несложный генератор словарей может подсчитать количество символов.

{letter: string.count(letter) for letter in unique_letters}


unique_letters формируем с помощью set(string).

показать ответы
1
DELETED
Автор поста оценил этот комментарий

Был уверен, что "Counter" ломает порядок расположения знаков относительно введенной строки. Оказывается, что нет, и эту функцию можно использовать. Удалил лишнюю функцию, так как Counter её заменяет полностью, и объявлять дополнительную функцию чтобы включить Counter и потом вызывать её в принципе не имеет смысла.


Спасибо за разбор кода!


Попытка номер 3.

Код: https://www.codepile.net/pile/Mj2v6xjR

Иллюстрация к комментарию
раскрыть ветку (1)
1
Автор поста оценил этот комментарий

Вот это уже прямо похоже на правду) Скорее всего, можно и ещё поковыряться, но уже не буду вас мучить. Почувствовали же разницу между исходным и финальным вариантом?

показать ответы
1
Автор поста оценил этот комментарий

Хочу порекомендовать typer. https://typer.tiangolo.com/

Он основан на click, но работает на аннотации типов. Он написан автором FastAPI, так что там поддерживаются те же идеи

раскрыть ветку (1)
1
Автор поста оценил этот комментарий

Офигенная вещь, спасибо! Под капотом rich, который рассматривал в одном из прошлых постов, то есть typer ещё и косметический ремонт для консоли проводит. На первый взгляд выглядит здорово, позже закопаюсь поглубже.

Иллюстрация к комментарию
0
DELETED
Автор поста оценил этот комментарий

Попытка номер 2.

Разбил на больше функций, сократил количество строк и "if".


Code: https://www.codepile.net/pile/rg2oOj84

Иллюстрация к комментарию
раскрыть ветку (1)
1
Автор поста оценил этот комментарий

Вектор движения верный, но есть ещё пара моментов.

1. Зачем функция, которая убирает из строки пробелы и приводит к нижнему регистру, таскает везде строку case? Получается перегруженная функция, которая вместо выполнения 1 чётко оформленной задачи пытается делать 2 разных дела одновременно.

В том месте, откуда эта функция вызывается, известно значение ignore_case. Просто используйте его тогда, когда будете формировать расширенный вывод для --verbose. То есть не стоит смешивать логику из блоков "вывод на экран" и "подготовка данных".

2. Попробуйте использовать множество и генератор словаря вместо хитровыделанной конструкции с генератором списков и not in chars.

показать ответы
2
DELETED
Автор поста оценил этот комментарий

Спасибо за супер полезный для меня пост.

Это то, что я хотел изучить, но руки не доходили.


Вроде работает =).

Ссылка: https://www.codepile.net/pile/l5eDqamr

Иллюстрация к комментарию
раскрыть ветку (1)
1
Автор поста оценил этот комментарий

Очень приятно видеть, что посты приносят пользу :)

Код действительно вроде бы работает) Но его можно сделать проще и короче. Попробуйте более чётко разделить всю логику на отдельные блоки:
1. Начальная подготовка данных;
2. Подсчёт букв;
3. Вывод на экран в нужном формате.

Сейчас эти блоки тесно переплетаются друг с другом, и это влечёт за собой обилие if/else и достаточно глубокую вложенность. Но задачу по формированию словаря вида {'М': 1, ...} можно решить в 5 строк кода, содержащих всего 1 if. Ну или 7 строк, если учитывать пустые строки, добавленные для красоты)

После того, как словарь будет сформирован, останется лишь вывести его на экран в нужном виде. Тут уже можно и сортировку учесть, и --verbose. Попробуйте)

показать ответы
0
Автор поста оценил этот комментарий
Урезонил.
раскрыть ветку (1)
1
Автор поста оценил этот комментарий

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

1
Автор поста оценил этот комментарий

https://click.palletsprojects.com/en/8.1.x/why/#why-not-argp...
Вот тут и написано...

Click is internally based on optparse instead of argparse.
раскрыть ветку (1)
2
Автор поста оценил этот комментарий

Ну не знаю, выглядит может и проще чем argparse... Однако, они сами пишут, что Click основан на optparse, который в новых версиях python - deprecated. Стоит ли подтягивать его в новые проекты - хз.


С другой стороны, основан не значит, что использует. Да и кол-во звездочек намекает, что это мало кого заботит :)
раскрыть ветку (1)
1
Автор поста оценил этот комментарий
Это где такое написано? В официальной доке обратное говорится: у них своя реализация парсинга аргументов, не зависящая ни от optparse, ни от argparse.
показать ответы