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.
См. также
Создание объектов 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(). Этот входной пункт поддерживается для обратной совместимости.
Преобразование объектов ST
Объекты ST, независимо от входных данных, используемых для их создания, могут быть преобразованы в синтаксические деревья, представленные деревьями списков или кортежей, или могут быть скомпилированы в исполняемые объекты кода. Синтаксические деревья могут быть извлечены с или без информации о номере строки.
-
parser.st2list(st, line_info=False, col_info=False) -
Эта функция принимает объект ST от вызывающей стороны в st и возвращает список Python, представляющий эквивалентное синтаксическое дерево. Результирующее представление списка может использоваться для проверки или создания нового синтаксического дерева в форме списка. Эта функция не завершается ошибкой, пока доступна память для построения представления списка. Если синтаксическое дерево будет использоваться только для проверки, следует использовать
st2tuple(), чтобы уменьшить потребление и фрагментацию памяти. Когда требуется представление списка, эта функция значительно быстрее, чем извлечение представления кортежа и преобразование его в вложенные списки.Если line_info равно true, информация о номере строки будет включена для всех терминальных токенов в качестве третьего элемента списка, представляющего токен. Обратите внимание, что указанный номер строки соответствует строке, в которой токен заканчивается. Эта информация опускается, если флаг не указан или ложный.
-
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. Большинство причин сбоя компиляции можно диагностировать программно путем проверки дерева разбора.
Запросы к объектам ST
Предоставляются две функции, которые позволяют приложению определить, был ли объект ST создан как выражение или набор инструкций. Ни одна из этих функций не может использоваться для определения того, был ли объект ST создан из исходного кода с помощью expr() или suite() или из дерева разбора с помощью sequence2st().
-
parser.isexpr(st) -
Когда st представляет собой
'eval'форму, эта функция возвращаетTrue, в противном случае возвращаетFalse. Это полезно, так как объекты кода обычно нельзя запросить об этой информации с помощью имеющихся встроенных функций. Обратите внимание, что объекты кода, созданные функциейcompilest(), также нельзя запросить таким образом, и они идентичны тем, которые созданы встроенной функциейcompile().
-
parser.issuite(st) -
Эта функция отражает
isexpr()в том, что она сообщает, представляет ли объект ST'exec'форму, обычно называемую «набором инструкций». Не следует полагать, что эта функция эквивалентнаnot isexpr(st), так как в будущем могут быть добавлены дополнительные фрагменты синтаксиса.
Исключения и обработка ошибок
Модуль парсера определяет одно исключение, но также может передавать другие встроенные исключения из других частей среды выполнения Python. Смотрите каждую функцию для получения информации об исключениях, которые она может вызвать.
-
exception parser.ParserError -
Исключение, возбуждаемое, когда происходит сбой в модуле парсера. Обычно оно возникает при сбоях валидации, а не при возникновении встроенного исключения
SyntaxErrorво время обычного разбора. Аргумент исключения — это либо строка, описывающая причину сбоя, либо кортеж, содержащий последовательность, вызвавшую сбой из дерева разбора, переданного вsequence2st(), и пояснительная строка. Вызовыsequence2st()должны уметь обрабатывать оба типа исключений, в то время как вызовы других функций в модуле будут знать только значения простых строк.
Обратите внимание, что функции compilest(), expr() и suite() могут вызвать исключения, которые обычно вызываются процессом разбора и компиляции. К ним относятся встроенные исключения MemoryError, OverflowError, SyntaxError и SystemError. В этих случаях эти исключения несут весь обычно связанный с ними смысл. Обратитесь к описаниям каждой функции для получения подробной информации.
Объекты 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).
Пример: Эмуляция 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.7/library/parser.html