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.
См. также
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(). Этот входной пункт поддерживается для обратной совместимости.
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. Большинство причин сбоя компиляции могут быть диагностированы программно путем проверки дерева разбора.
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), так как в будущем могут быть добавлены дополнительные фрагменты синтаксиса.
4. Исключения и обработка ошибок
Модуль парсера определяет одно исключение, но также может передавать другие встроенные исключения из других частей среды выполнения Python. См. каждую функцию для получения информации об исключениях, которые она может вызвать.
-
exception parser.ParserError -
Исключение, которое возникает при ошибке в модуле парсера. Оно обычно возникает при ошибках валидации, а не встроенном
SyntaxError, возникающем во время обычного разбора. Аргумент исключения — это либо строка, описывающая причину ошибки, либо кортеж, содержащий последовательность, вызвавшую ошибку из дерева разбора, переданного вsequence2st(), и пояснение. Вызовыsequence2st()должны уметь обрабатывать оба типа исключений, в то время как вызовы других функций в модуле будут знать только про значения строк.
Обратите внимание, что функции compilest(), expr() и suite() могут вызывать исключения, которые обычно генерируются процессом разбора и компиляции. К ним относятся встроенные исключения MemoryError, OverflowError, SyntaxError и SystemError. В этих случаях эти исключения сохраняют всё своё обычное значение. Обратитесь к описаниям каждой функции для получения подробной информации.
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).
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.5/library/parser.html