parser — Доступ к синтаксическим деревьям Python
Модуль parser предоставляет интерфейс к внутреннему парсеру и компилятору байткода Python. Основное назначение этого интерфейса — позволить коду Python редактировать синтаксическое дерево Python-выражения и создавать исполняемый код из него. Это лучше, чем попытка парсить и модифицировать произвольный фрагмент кода Python как строку, потому что парсинг выполняется так же, как и при формировании приложения. Это также быстрее.
Примечание
Начиная с Python 2.5, гораздо удобнее работать с этапом генерации и компиляции абстрактного синтаксического дерева (AST), используя модуль ast.
Необходимо отметить несколько важных моментов, касающихся этого модуля и использования созданных структур данных. Это не учебник по редактированию синтаксических деревьев кода Python, но представлены некоторые примеры использования модуля parser.
Самое главное, требуется хорошее понимание грамматики Python, обрабатываемой внутренним парсером. Для получения полной информации о синтаксисе языка, обратитесь к Справочнику по языку Python. Сам парсер создаётся на основе грамматической спецификации, определённой в файле Grammar/Grammar в стандартном дистрибутиве Python. Синтаксические деревья, хранящиеся в объектах ST, созданных этим модулем, являются фактическим выходом внутреннего парсера при создании с помощью функций expr() или suite(), описанных ниже. Объекты ST, созданные с помощью sequence2st(), надёжно имитируют эти структуры. Обратите внимание, что значения последовательностей, которые считаются «правильными», будут различаться в разных версиях Python по мере пересмотра формальной грамматики языка. Однако перемещение кода из одной версии Python в другую в виде исходного текста всегда позволит создать правильные синтаксические деревья в целевой версии, единственным ограничением является то, что миграция к более старой версии интерпретатора не будет поддерживать более новые конструкции языка. Синтаксические деревья обычно несовместимы между версиями, в то время как исходный код всегда совместим в будущем.
Каждый элемент последовательностей, возвращаемых st2list() или st2tuple(), имеет простую форму. Последовательности, представляющие нетерминальные элементы в грамматике, всегда имеют длину больше единицы. Первый элемент — это целое число, которое идентифицирует производство в грамматике. Эти числа получают символические имена в файле заголовков C Include/graminit.h и модуле Python symbol. Каждый дополнительный элемент последовательности представляет собой компонент производства, распознанный в входной строке: это всегда последовательности, имеющие такую же форму, что и родительская. Важный аспект этой структуры, который следует отметить, заключается в том, что ключевые слова, используемые для идентификации типа родительского узла, такие как ключевое слово if в if_stmt, включаются в дерево узлов без каких-либо специальных обработок. Например, ключевое слово if представлено кортежем (1, 'if'), где 1 — числовое значение, связанное со всеми NAME токенами, включая имена переменных и функций, определённые пользователем. В альтернативной форме, возвращаемой при запросе информации о строке, тот же токен может быть представлен как (1, 'if', 12), где 12 представляет собой номер строки, в которой был найден терминальный символ.
Терминальные элементы представляются аналогично, но без дочерних элементов и с добавлением идентифицированного исходного текста. Пример с ключевым словом if выше является характерным. Различные типы терминальных символов определены в файле заголовков C Include/token.h и модуле Python token.
Объекты ST не обязаны поддерживать функциональность этого модуля, но предоставляются для трёх целей: позволить приложению амортизировать стоимость обработки сложных синтаксических деревьев, предоставить представление синтаксического дерева, которое сохраняет объём памяти по сравнению с представлением Python в виде списка или кортежа, и облегчить создание дополнительных модулей на C для манипулирования синтаксическими деревьями. В Python можно создать простой «обёртковый» класс для скрытия использования объектов ST.
Модуль parser определяет функции для нескольких различных целей. Самые важные цели — создание объектов ST и преобразование объектов ST в другие представления, такие как синтаксические деревья и объекты исполняемого кода, но также существуют функции для запроса типа синтаксического дерева, представленного объектом ST.
См. также
32.1.1. Создание объектов ST
Объекты ST могут быть созданы из исходного кода или из синтаксического дерева. При создании объекта ST из исходного кода используются разные функции для создания форм 'eval' и 'exec'.
-
parser.expr(source) -
Функция
expr()анализирует параметр source так, как будто он был введён вcompile(source, 'file.py', 'eval'). Если анализ успешен, создаётся объект ST для хранения внутреннего представления синтаксического дерева, в противном случае генерируется соответствующее исключение.
-
parser.suite(source) -
Функция
suite()анализирует параметр source так, как будто он был введён вcompile(source, 'file.py', 'exec'). Если анализ успешен, создаётся объект ST для хранения внутреннего представления синтаксического дерева, в противном случае генерируется соответствующее исключение.
-
parser.sequence2st(sequence) -
Эта функция принимает синтаксическое дерево, представленное последовательностью, и строит внутреннее представление, если это возможно. Если она может подтвердить, что дерево соответствует грамматике Python и все узлы являются допустимыми типами узлов в используемой версии Python, то из внутреннего представления создаётся и возвращается объект ST. Если при создании внутреннего представления возникла проблема или дерево не может быть проверено, генерируется исключение
ParserError. Не следует предполагать, что объект ST, созданный таким образом, будет успешно скомпилирован; при передаче объекта ST вcompilest()могут быть инициированы обычные исключения, возникающие при компиляции. Это может указывать на проблемы, не связанные с синтаксисом (например, исключениеMemoryError), но также может быть связано с конструкциями, например, результатом анализаdel f(0), которые выходят за пределы парсера Python, но проверяются компилятором байткода.Последовательности, представляющие терминальные токены, могут быть представлены либо в виде двухэлементных списков вида
(1, 'name'), либо в виде трёхэлементных списков вида(1, 'name', 56). Если третий элемент присутствует, он предполагается как допустимый номер строки. Номер строки может быть указан для любого подмножества терминальных символов в входном дереве.
-
parser.tuple2st(sequence) -
Эта функция эквивалентна
sequence2st(). Этот входной пункт поддерживается для обратной совместимости.
32.1.2. Преобразование объектов ST
Объекты ST, независимо от используемого для их создания входного данных, могут быть преобразованы в синтаксические деревья, представленные деревьями списков или кортежей, или могут быть скомпилированы в объекты исполняемого кода. Синтаксические деревья могут быть извлечены с или без информации о номерах строк.
-
parser.st2list(st, line_info=False, col_info=False) -
Эта функция принимает объект ST от вызывающей стороны в st и возвращает Python-список, представляющий эквивалентное синтаксическое дерево. Результирующее представление в виде списка может использоваться для проверки или создания нового синтаксического дерева в форме списка. Эта функция не завершается ошибкой, пока доступна память для построения представления в виде списка. Если синтаксическое дерево используется только для проверки,
st2tuple()следует использовать для уменьшения потребления и фрагментации памяти. Когда требуется представление в виде списка, эта функция значительно быстрее, чем извлечение представления в виде кортежа и преобразование его в вложенные списки.Если line_info равно True, информация о номерах строк будет включена для всех терминальных токенов как третий элемент списка, представляющего токен. Обратите внимание, что указанный номер строки обозначает строку, в которой токен заканчивается. Эта информация пропускается, если флаг равен False или отсутствует.
-
parser.st2tuple(st, line_info=False, col_info=False) -
Эта функция принимает объект ST от вызывающего кода в st и возвращает кортеж Python, представляющий эквивалентное дерево разбора. Помимо возвращения кортежа вместо списка, эта функция идентична
st2list().Если line_info имеет значение true, информация о номере строки будет включена для всех терминальных токенов в качестве третьего элемента списка, представляющего токен. Эта информация опущена, если флаг имеет значение false или опущен.
-
parser.compilest(st, filename='<syntax-tree>') -
Компилятор байткода Python может быть вызван на объекте ST для создания объектов кода, которые могут быть использованы в качестве части вызова встроенных функций
exec()илиeval(). Эта функция предоставляет интерфейс к компилятору, передавая внутреннее дерево разбора из st в анализатор, используя имя файла исходного кода, указанное в параметре filename. Значение по умолчанию, предоставленное для filename, указывает, что исходный код был объектом ST.Компиляция объекта ST может привести к исключениям, связанным с компиляцией; примером является
SyntaxError, вызванный деревом разбора дляdel f(0): это утверждение считается законным в формальной грамматике Python, но не является законной конструкцией языка.SyntaxError, поднятый для этого условия, фактически генерируется компилятором байткода Python, поэтому он может быть поднят на этом этапе модулемparser. Большинство причин сбоя компиляции могут быть диагностированы программно путем проверки дерева разбора.
32.1.3. Запросы к объектам ST
Предоставляются две функции, которые позволяют приложению определить, был ли объект ST создан как выражение или блок кода. Ни одна из этих функций не может быть использована для определения того, был ли объект ST создан из исходного кода через expr() или suite(), или из дерева разбора через sequence2st().
-
parser.isexpr(st) -
Когда st представляет форму
'eval', эта функция возвращает true, в противном случае — false. Это полезно, так как объекты кода обычно не могут быть запрошены для этой информации с помощью существующих встроенных функций. Обратите внимание, что объекты кода, созданные функциейcompilest(), также не могут быть запрошены таким образом и идентичны объектам кода, созданным встроенной функциейcompile().
-
parser.issuite(st) -
Эта функция аналогична
isexpr()в том, что она сообщает, представляет ли объект ST форму'exec', обычно называемую «блоком кода». Не следует предполагать, что эта функция эквивалентнаnot isexpr(st), так как в будущем могут быть добавлены дополнительные фрагменты синтаксиса.
32.1.4. Исключения и обработка ошибок
Модуль парсера определяет одно исключение, но также может передавать другие встроенные исключения из других частей среды выполнения Python. См. каждую функцию для получения информации об исключениях, которые она может вызвать.
-
exception parser.ParserError -
Исключение, которое возникает, когда происходит сбой в модуле парсера. Как правило, это происходит при ошибках валидации, а не при встроенном
SyntaxError, возникающем во время обычного разбора. Аргумент исключения — это либо строка, описывающая причину сбоя, либо кортеж, содержащий последовательность, вызвавшую сбой из дерева разбора, переданного функцииsequence2st(), и поясняющая строка. Вызовамsequence2st()необходимо уметь обрабатывать оба типа исключений, в то время как вызовам других функций модуля потребуется знать только строковые значения.
Обратите внимание, что функции compilest(), expr() и suite() могут вызывать исключения, которые обычно возникают при разборе и компиляции. К ним относятся встроенные исключения MemoryError, OverflowError, SyntaxError и SystemError. В этих случаях эти исключения сохраняют всё обычное значение. См. описания каждой функции для получения подробной информации.
32.1.5. Объекты ST
Поддерживаются упорядочивающие и сравнения на равенство между объектами ST. Также поддерживается сохранение объектов ST (с использованием модуля pickle).
-
parser.STType -
Тип объектов, возвращаемых функциями
expr(),suite()иsequence2st().
Объекты ST имеют следующие методы:
-
ST.compile(filename='<syntax-tree>') -
То же, что и
compilest(st, filename).
-
ST.isexpr() -
То же, что и
isexpr(st).
-
ST.issuite() -
То же, что и
issuite(st).
-
ST.tolist(line_info=False, col_info=False) -
То же, что и
st2list(st, line_info, col_info).
-
ST.totuple(line_info=False, col_info=False) -
То же, что и
st2tuple(st, line_info, col_info).
32.1.6. Пример: Эмуляция compile()
Хотя между разбором и генерацией байткода могут выполняться многие полезные операции, простейшей операцией является ничегонеделание. В этом случае использование модуля parser для создания промежуточной структуры данных эквивалентно коду
>>> code = compile('a + 5', 'file.py', 'eval')
>>> a = 5
>>> eval(code)
10
Эквивалентная операция с использованием модуля parser несколько длиннее и позволяет сохранить промежуточное внутреннее дерево разбора в виде объекта ST:
>>> import parser
>>> st = parser.expr('a + 5')
>>> code = st.compile('file.py')
>>> a = 5
>>> eval(code)
10
Приложение, которому нужны как объекты ST, так и объекты кода, может упаковать этот код в легкодоступные функции:
import parser
def load_suite(source_string):
st = parser.suite(source_string)
return st, st.compile()
def load_expression(source_string):
st = parser.expr(source_string)
return st, st.compile()
© 2001–2020 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.6/library/parser.html