parser — Доступ к синтаксическим деревьям Python
Модуль parser предоставляет интерфейс к внутреннему парсеру и компилятору байткода Python. Основное назначение этого интерфейса — позволить коду Python редактировать синтаксическое дерево выражения Python и создавать исполняемый код из него. Это лучше, чем пытаться парсить и изменять произвольный фрагмент кода Python как строку, поскольку парсинг выполняется так же, как и при формировании приложения. Это также быстрее.
Предупреждение
Модуль parser устарел и будет удалён в будущих версиях Python. В большинстве случаев можно использовать генерацию и компиляцию абстрактного синтаксического дерева (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, информация о номерах строк будет включена для всех терминальных токенов в качестве третьего элемента списка, представляющего токен. Обратите внимание, что указанный номер строки указывает на строку, в которой токен заканчивается. Эта информация пропускается, если флаг имеет значение 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. Большинство причин сбоя компиляции можно диагностировать программно путём проверки дерева разбора.
Запросы к объектам 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–2022 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.9/library/parser.html