Документация Python неофициальный перевод
Содержание страницы

parser – Доступ к деревьям разбора Pythonparser – Access Python parse trees


Модуль parser предоставляет интерфейс к внутреннему синтаксическому анализатору 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-объектом.

См. также

Модуль symbol

Полезные константы, представляющие внутренние узлы дерева разбора.

Модуль token

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

Создание ST-объектовCreating ST Objects

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-объектовConverting ST Objects

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. Большинство причин сбоя компиляции можно диагностировать программно, проверив синтаксическое дерево.

Запросы к объектам STQueries on ST Objects

Предоставляются две функции, которые позволяют приложению определить, был ли ST создан как выражение или как блок. Ни одна из этих функций не может быть использована для определения того, был ли ST создан из исходного кода через expr() или suite(), или из синтаксического дерева через sequence2st().

parser.isexpr(st)

Когда st представляет форму 'eval', эта функция возвращает True, иначе возвращает False. Это полезно, поскольку объекты кода обычно не могут быть опрошены на предмет этой информации с помощью существующих встроенных функций. Обратите внимание, что объекты кода, созданные функцией compilest(), также нельзя так опросить, и они идентичны тем, что создаются встроенной функцией compile().

parser.issuite(st)

Эта функция аналогична isexpr() в том, что она сообщает, представляет ли объект ST форму 'exec', обычно называемую "блоком". Небезопасно предполагать, что эта функция эквивалентна not isexpr(st), так как в будущем могут поддерживаться дополнительные синтаксические фрагменты.

Исключения и обработка ошибокExceptions and Error Handling

Модуль parser определяет одно исключение, но также может передавать другие встроенные исключения из других частей среды выполнения Python. Информацию об исключениях, которые может вызывать каждая функция, смотрите в её описании.

exception parser.ParserError

Исключение, возбуждаемое при сбое в модуле parser. Обычно оно возникает из-за ошибок валидации, а не из-за встроенного исключения SyntaxError, возбуждаемого при обычном разборе. Аргумент исключения – либо строка, описывающая причину сбоя, либо кортеж, содержащий последовательность, вызвавшую сбой (из синтаксического дерева, переданного в sequence2st()), и пояснительную строку. Вызовы sequence2st() должны уметь обрабатывать оба типа исключений, в то время как вызовы других функций модуля должны быть готовы только к простым строковым значениям.

Обратите внимание, что функции compilest(), expr() и suite() могут возбуждать исключения, которые обычно возбуждаются в процессе разбора и компиляции. К ним относятся встроенные исключения MemoryError, OverflowError, SyntaxError и SystemError. В этих случаях такие исключения несут всю обычную смысловую нагрузку. За подробной информацией обращайтесь к описанию каждой функции.

Объекты STST Objects

Поддерживаются упорядоченные сравнения и сравнения на равенство между объектами 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()Example: Emulation of 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()