Для написания интерфейсов командой строки лучше использовать библиотеки, которые упростят вам жизнь и значительно ускорят разработку. Сегодня мы рассмотрим Google Fire — одну из таких библиотек.
3К открытий3К показов
Сегодня мы рассмотрим библиотеку Fire, которая позволяет автоматизировать интерфейсы командной строки (CLI) на Python.
Fire — самая популярная после TensorFlow разработка для Python, которую Google выложил в открытый доступ:
Правда, она не настолько популярна…
Что интересно в библиотеке TensorFlow, так это то, что на момент её выхода на рынке уже было несколько популярных библиотек глубокого обучения (Theano, Caffe и Torch). Несмотря на это, TensorFlow сразу начал набирать популярность, посмотрите на активность Stack Overflow:
В этом плане Fire похож на Tensorflow, так как и до него было уже достаточно много хороших инструментов для автоматизации интерфейсов командной строки на Python. Будет интересно посмотреть, примут ли разработчики Fire.
Примечание После использования Fire в течение нескольких недель и сравнения с другими вариантами вроде Click, становится понятно, что Fire больше подходит для быстрой разработки, так как в нём отсутствуют многие функции других CLI. Тем не менее, новые функции находятся в разработке. В первом релизе IPython был обязательной зависимостью, что приводило к долгой загрузке даже простых скриптов, но сейчас в нём нет необходимости!
Пример приложения с Fire
Fire можно установить с помощью pip:
pip install fire
Документацию можно найти на GitHub. В ней содержится проницательная заметка:
Почему библиотека называется Fire?Когда вы вызываете Fire, она выстреливает (fire off, выполняет) вашей командой.
Мы можем выполнить команду, вызвав fire.Fire(my_object), где my_object может быть функцией, классом или другим объектом.
Теперь пора делать приложение. Мы напишем генератор случайного выбора. Функция random_sample будет вычисляться через Fire. Как мы увидим, значения, возвращённые функцией, будут выведены в консоль.
Посмотрим на код:
'''
Функция для генерации случайного выбора.
Использование:
Для получения инструкций по использованию введите следующую команду:
>>> python3 random_sample.py -- --help
'''
import fire
import numpy as np
def random_sample(choices, num_samples=1, seed=None):
'''
Возвращает случайный выбор из входных данных.
choices : tuple
Варианты для выбора.
num_samples : int
Количество возвращаемых значений.
seed : int
Переменная для инициализации генератора случайных чисел. Используйте None для получения случайного значения.
'''
num_samples = int(num_samples)
seed = int(seed) if str(seed).isnumeric() else seed
print(f'Варианты для выбора: {repr(choices)}')
print(f'Выбираю {num_samples} значений')
print(f'Seed: {seed}')
np.random.seed(seed)
samples = np.random.choice(choices, size=num_samples)
print('Результат:')
return '\n'.join(samples)
def main():
fire.Fire(random_sample)
if __name__ == '__main__':
main()
Примечание переводчика Код в данной статье написан на Python 3.6, работоспособность на более ранних версиях не гарантируется.
Мы передаём нашу функцию random_sample методу Fire, который автоматически создаёт аргументы командной строки для параметров функции. Нам не нужно писать инструкции по применению скрипта: пользователь может ввести python3 random_sample.py -- --help и увидеть следующий вывод:
$ python3 random_sample.py -- --help
Type: function
String form: <function random_sample at 0x1003bcf28>
File: ~/Documents/blog-posts/google-fire/random-sample/random_sample.py
Line: 10
Docstring: Возвращает случайный выбор из входных данных
Пример использования скрипта:
>>> python3 random_sample.py 'Bohr, Schrödinger, Einstein, Dirac' --num-samples 4 --seed 1905
Варианты для выбора: ('Bohr', 'Schrödinger', 'Einstein', 'Dirac')
Выбираю 4 значений
Seed: 1905
Результат:
Dirac
Einstein
Dirac
Schrödinger
Примечание Если вы хотите запускать скрипт как исполняемый файл (например, ./random_sample.py вместо python3 random_sample.py), то добавьте в начале скрипта строку #!/usr/bin/env python и разрешите исполнение скрипта с помощью команды chmod +x random_sample.py.
Интерактивный режим
Что в Fire интересно, так это то, что он может перенести вас в среду IPython REPL. Для этого вам просто нужно добавить -- --interactive в конце вызова вашего скрипта. Например:
$ python3 random_sample.py 'Bohr, Schrödinger, Einstein, Dirac' --num-samples 4 --seed 1905 -- --interactive
Варианты для выбора: ('Bohr', 'Schrödinger', 'Einstein', 'Dirac')
Выбираю 4 значений
Seed: 1905
Результат:
Fire is starting a Python REPL with the following objects:
Modules: fire, np
Objects: component, main, random_sample.py, random_sample, result, self, trace
Python 3.5.2 |Anaconda 4.2.0 (x86_64)| (default, Jul 2 2016, 17:52:12)
Type "copyrigth", "credits" or "license" for more information.
IPython 5.1.0 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features
%quickref -> Quick reference.
help -> Python's own help system.
object -> Details about 'object', use 'object??' for extra details.
In [1]: print(result)
Dirac
Einstein
Dirac
Schrödinger
Запускаем random_sample.py.
Показываем вывод random_sample.py.
Заметили модуль и объекты, которые были загружены?
Запускаем интерпретатор IPython.
Выводим результат.
Данные, возвращённые вызовом функции, теперь расположены в памяти, так же, как и сама функция. Ниже мы выводим документацию и снова запускаем генератор случайного выбора:
IPython 5.1.0 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features
%quickref -> Quick reference.
help -> Python's own help system.
object -> Details about 'object', use 'object??' for extra details.
In [1]: print(result)
Dirac
Einstein
Dirac
Schrödinger
In [2]: print(random_sample.__doc__)
Возвращает случайный выбор из входных данных.
choices : str
Варианты для выбора.
num_samples : int
Количество возвращаемых значений.
seed : int
Переменная для инициализации генератора случайных чисел. Используйте None для получения случайного значения.
In [3]: sample_2 = random_sample(('Bohr', 'Schrödinger'), num_samples=2, seed=3)
Варианты для выбора: ('Bohr', 'Schrödinger')
Выбираю 2 значений
Seed: 3
Результат:
In [4]: print(sample_2)
Bohr
Bohr
Аргументы для выбора передаются как кортеж, а во время использования командной строки они передаются как строка:
Вы можете передать любой объект модулю Fire, и библиотека сгенерирует CLI. Вот пример, в котором мы используем класс:
'''
Класс для получения данных с вики-страницы.
Для получения инструкций по использованию введите следующие команды:
>>> python3 wiki_page.py -- --help
>>> python3 wiki_page.py get-html-element -- --help
'''
import fire
import requests
import re
class WikiPage():
'''
Запрашивает страницу из Википедии.
page : str
URL страницы. По умолчанию возвращает случайную страницу.
'''
def __init__(self, page='https://en.wikipedia.org/wiki/Special:Random'):
page = requests.get(page)
self.page = page
self.url = page.url
self.status_code = page.status_code
def get_html_element(self, element):
''' Получить HTML-тег вроде title, h1, p, etc... '''
try:
# Пытаемся достать тег с помощью регулярного выражения.
text = re.findall(r'<{name}[^>]*>(.*)(?:</{name})'.format(name=element),
self.page.text)[0]
except Exception as e:
print(f'Не могу найти тег {element} на странице' )
raise e
return text
def main():
fire.Fire(WikiPage)
if __name__ == '__main__':
main()
Наш класс WikiPage запрашивает страницу из Википедии, и затем функция get_html_element ищет HTML-элемент на этой странице.
Примечание Для поиска HTML-элементов лучше использовать специальные библиотеки вроде BeautifulSoup, а не регулярные выражения.
Также мы можем вызывать модули прямо из командной строки:
$ python3 wiki_page.py get-html-element -- --help
Type: WikiPage
String form: <bound method WikiPage.get_html_elememt of <__main__.WikiPage object at 0x104d555c0>>
File: ~/Documents/blog-posts/google-fire/get-wiki-page/wiki_page.py
LineL 24
Docstring: Получить HTML-тег вроде title, h1, p, etc...
page : str
URL страницы. По умолчанию возвращает случайную страницу.
Usage: wiki_page.py get-html-element ELEMENT
wiki_page.py get-html-element ELEMENT
Например:
>>> python3 wiki_page.py --page https://en.wikipedia.org/wiki/History_of_quantum_mechanics get-html-element title
History of quantum mechanics - Wikipedia
Современные разработчики все чаще обращаются к редким языкам программирования, чтобы решить специфические задачи проекта. Разбираемся, как и когда их нужно использовать.
Мы погрузились в мрачный мир фантазий и представили, какие языки программирования и роли могли бы выбрать самые известные злодеи хоррор-фильмов, если бы они ворвались в IT.