Использование стандартной библиотеки для преобразования сигнатуры функции в парсер аргументов консоли
При работе над проектами, ориентированными на машины, вам необходимо написать множество специальных фрагментов кода: загрузка и чтение / распаковка данных, преобразование данных в удобный формат, построение конвейеров обучения и многое другое. Вы, вероятно, повторно используете некоторые из этих сценариев, но остальные выбросите после нескольких итераций или при переключении на другую задачу.
Вам нужно как-то параметризовать свои скрипты, то есть настроить папки ввода / вывода, настроить параметры обучения или заменить одну архитектуру на другую. Для этой цели вы должны написать правильный анализатор аргументов, который преобразует ваши параметры интерфейса командной строки в переменные сценария или параметры функции. Поэтому каждый раз, когда у вас есть какой-то фрагмент, вы пишете много повторяющегося шаблонного кода, который не будет жить долго. Было бы здорово, если бы вы могли легко преобразовать произвольную функцию Python в инструмент командной строки, не так ли?
Готов поспорить, что сейчас многие читатели скажут, что существует отличная Fire
библиотека, которая преобразует произвольную функцию или класс Python в готовый для консоли скрипт. Однако мне это кажется немного громоздким, и я делаю много вещей, которые мне не нужны. Поэтому мне было интересно, насколько сложно может быть написать решение «сделай сам», менее мощное, но простое и лучше адаптированное к моим потребностям? Ответ: совсем не сложно!
В этом посте я собираюсь показать, как можно использовать модуль Python inspect
для динамического создания ArgumentParser
экземпляров, используя менее нескольких десятков строк кода.
TL; DR: Вот ссылка на репозиторий, которая включает немного расширенную версию кода, описанного в этом посте, и позволяет создавать специальные утилиты CLI из любой функции Python с помощью команды
python -m ancli path.to.module:function
.
Постановка цели
Рассмотрим следующий фрагмент, который просматривает папку и объединяет ее содержимое в один файл.
Представим, что вы хотите преобразовать его в сниппет, который можно было бы запускать как консольную программу. Вы хотели бы сделать это с минимальными усилиями. Вы можете использовать argparse
и добавлять каждый параметр вручную, но это будет очень утомительный процесс, в основном связанный с «дублированием» каждого параметра функции в качестве параметра интерфейса командной строки. Должен быть способ получше.
Что, если бы мы могли использовать волшебную make_cli
функцию, которая должна преобразовать этот сценарий в работающую консольную утилиту? Как показано на гифке ниже.
Что ж, у нас нет такой функции в стандартной библиотеке, но мы легко можем написать ее сами.
Проверка подписи функции
Для достижения цели, заявленной в предыдущем разделе, нам нужно (а) выяснить, какие аргументы принимает функция, (б) использовать эту информацию для создания экземпляра argparse
, который анализирует ввод консоли, и (в) вызвать функцию с проанализированными параметрами. .
К счастью, у нас есть встроенный модуль inspect
, позволяющий читать подпись любого вызываемого Python. Применим его к нашей concat
функции.
>>> import inspect >>> sig = inspect.signature(concat) >>> sig <Signature (folder: str, output: str = 'concat.txt', include_names: bool = True)> >>> for p in sig.parameters.values(): print(p) folder: str output: str = 'concat.txt' include_names: bool = True
Легко! Подпись дает нам доступ к именам параметров, их аннотациям и значениям по умолчанию. Это также помогает различать обязательные и необязательные параметры. По большей части это все, что нам нужно для создания парсера аргументов.
Генерация парсера
Теперь, когда у нас есть сигнатура функции, мы можем быстро выполнить ее итерацию и построить синтаксический анализатор. В следующем фрагменте показано, как это можно сделать.
Прежде всего, мы берем сигнатуру функции, как показано в строке 6
. Затем мы перебираем его параметры в цикле, объявленном в строках 9-30
. Мы используем атрибуты объектов inspect.Parameter
для доступа к аннотациям, типам (если есть) и значениям по умолчанию. Если значение по умолчанию недоступно, мы обрабатываем параметр как требуемый. Каждый параметр мы добавляем в парсер. Наконец, мы вызываем синтаксический анализатор и передаем проанализированные значения в функцию. Легкий!
Теперь давайте проверим, как это работает. Приведенный ниже фрагмент включает наши concat
и make_cli
функции и объединяет их для создания утилиты командной строки.
Вывод
Множество интересных проектов и инструментов, которые используют инспекцию, чтобы упростить процесс разработки. Различные IDE используют его для реализации основных моментов кода и советов. Анализаторы статического типа, такие как mypy
, помогают проверить правильность программы Python перед ее запуском. Библиотека sklearn
использует проверку для получения / установки параметров оценщика.
Хотя эти примеры не должны создавать впечатление, что возможности Python для отражения являются чем-то «волшебным» и полезны только при разработке сложной библиотеки машинного обучения. Это может быть очень полезный инструмент при работе над повседневными задачами и создании инструментов и приложений широкого спектра, от очень сложных до самых простых.
Вас интересует язык Python? Не можете жить без машинного обучения? Прочитали что-нибудь в Интернете?
Тогда, возможно, вас заинтересует мой блог, где я рассказываю о различных темах программирования и даю ссылки на учебники и руководства, которые мне показались интересными.