Tags: python

Генерация кода на питоне при помощи hy 0

1 Что такое Hy

Hy - диалект Лиспа, который встроен в питон.

Благодаря тому, что Hy трансформирует свой Лиспоподобный код в Абстрактное Синтаксическое Дерево (AST) питона, с помощью Hy весь прекрасный мир питона - на кончиках пальцев и в форме Лиспа.

2 О синтаксисе Hy, очень кратко

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

  1. Отступ не играет роли. Вместо этого - уровни вложенности в выражения из круглых скобочек.
  2. Во всех вызовах функций название функции попадает в скобки со списком аргументов на первое место; запятые в списке аргументов не используются.
  3. Все операторы записываются так, как будто они - функции.
  4. Двоеточия не используются.
  5. Литералы для строк и словарей работают как и раньше; строки записываются в двойных кавычках, кортежи выглядят как вызов функции ",".

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

3 Терминологические замечания

Следует отдельно оговорить используемую терминологию. Основные английские термины на английском - quoting, unquoting, quaziquoting, splicing, macro expansion. В переводе книги Practical Common Lisp на русский язык для них используются слова "цитирование", "расцитирование", "квазицитирование" - и для последнего из них - "раскрытие макросов". Я не считаю этот вариант перевода удобным.

В данном материале будут использованы в качестве переводов "скрытие" для quoting, "раскрытие" для unquoting, "квазискрытие" для quaziquoting, "структурное раскрытие" для splicing, "расширение макроса" для macro expansion.

В приведённых далее примерах кода, можно увидеть синтаксис этих операций:

'
скрытие; применяется к последующей форме Hy; вместо её выполнения она будет обработанакак как данные.
`
квазискрытие; более сложная форма скрытия, позволяющая строить более сложные синтаксические структуры.
~
раскрытие; так как , занята в питоне для конструктора кортежей, используемый символ отличается от традиционной для Лиспа запятой. Употребляется в квазискрытой форме и помещает в неё результат выполнения следующей за ней формы.
~@
структурное раскрытие; работает аналогично предыдущей операции со следующим различием: результат оценки формы должен быть списком, и его элементы помещаются в объемлющую квазискрытую форму.

Выполнение обозначает вызов функции если форма - список, и доступ к значению символа в противном случае; литералы при выполнении остаются сами собой.

Способ, которым производится генерация кода на питоне, состоит в получении эквивалентного AST и его последующем "дизассемблировании" в код на питоне.

Генерация кода на питоне с помощью hy 2

При генерации питоновского кода, в отличие, например, от написания макросов, для нас является важным, какие названия носят новые символы, т.е. в случае питона - имена вновь сгенерированных функций, классов, переменных. Другими словами, стандартный способ в лиспе ((gensym)) нам не подходит. Также в hy нет стандартного для многих лиспов (intern), служащего для превращения произвольной строки (с поправкой на ограничения по грамматике) в символ.

Collapse )

Поддельные объекты

Недавно пришлось озадачиться следующим вопросом - доступом к базе данных (postgres) для слива оттуда определённого рода интересных данных. В сущности, это решается одним sql-запросом, но с каких пор мы ищем лёгкие пути?

Поэтому было решено использовать уже имеющиеся orm-модели.

Проблема заключалась в следующем. Эти модели были получены класса SQLAlchemy пакета flask.ext.sqlalchemy, и потому имела место быть зависимость от flask. А объективно говоря, для подключения к БД и выполнения на нём запросов запуск веб-сервера не требуется.

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

Путём проб и ошибок, а также чтения кода был получен минимально необходимый объект, изображающий из себя сервер flask

class FakeApp(object):
    from flask.config import Config
    config = Config('.', {})
    extensions = {}
    debug = True
    import_name = 'fake'

    @staticmethod
    def teardown_request(func):
        return func

Инициализация его производится с помощью занесения в него конфигурации методом Config.from_object(), а связь с БД - вызовом на объекте SQLAlchemy его метода init_app, после чего фальшивый объект заносится в поле app экземпляра SQLAlchemy.

Можно только предположить что в нормальных условиях эту регистрацию проводит сам веб-сервер, проверив подключенные к нему расширения (одним из которых является и flask.ext.SQLAlchemy).