parser — Доступ к деревьям разбора Python
Модуль parser предоставляет интерфейс к внутреннему парсеру и компилятору байткода Python. Основное назначение этого интерфейса — позволить коду Python редактировать дерево разбора выражения Python и создавать исполняемый код из него. Это лучше, чем пытаться разобрать и изменить произвольный фрагмент кода Python как строку, потому что разбор выполняется так же, как и код приложения. Он также быстрее.
Примечание
Начиная с Python 2.5, гораздо удобнее работать со стадией генерации и компиляции абстрактного синтаксического дерева (AST), используя модуль ast.
Модуль parser экспортирует имена, документированные здесь, заменив «st» на «ast»; это наследие со времён, когда другого AST не было, и не имеет ничего общего с AST, найденным в Python 2.5. Это также причина, по которой ключевые аргументы функций называются *ast*, а не *st*. Функции «ast» были удалены в Python 3.
Несколько моментов следует учитывать при использовании созданных структур данных. Это не учебник по редактированию деревьев разбора кода 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(ast[, line_info]) -
Эта функция принимает объект ST от вызывающей стороны в ast и возвращает список Python, представляющий эквивалентное дерево разбора. Результирующее представление в виде списка может быть использовано для проверки или создания нового дерева разбора в виде списка. Эта функция не завершается ошибкой, пока есть доступная память для построения представления в виде списка. Если дерево разбора будет использоваться только для проверки,
st2tuple()следует использовать вместо него, чтобы уменьшить потребление памяти и фрагментацию. Когда требуется представление в виде списка, эта функция значительно быстрее, чем получение представления в виде кортежа и преобразование его во вложенные списки.Если line_info имеет значение true, информация о номере строки будет включена для всех терминальных токенов в качестве третьего элемента списка, представляющего токен. Обратите внимание, что указанный номер строки соответствует строке, в которой токен заканчивается. Эта информация опускается, если флаг имеет значение false или отсутствует.
-
parser.st2tuple(ast[, line_info]) -
Эта функция принимает объект ST от вызывающей стороны в ast и возвращает кортеж Python, представляющий эквивалентное дерево разбора. Помимо возврата кортежа вместо списка, эта функция идентична
st2list().Если line_info имеет значение true, информация о номере строки будет включена для всех терминальных токенов в качестве третьего элемента списка, представляющего токен. Эта информация опускается, если флаг имеет значение false или отсутствует.
-
parser.compilest(ast, filename='<syntax-tree>') -
Компилятор байткода Python может быть вызван для объекта ST, чтобы получить объекты кода, которые могут быть использованы как часть инструкции
execили вызова встроенной функцииeval(). Эта функция предоставляет интерфейс к компилятору, передавая внутреннее дерево разбора из ast в анализатор, используя имя файла исходного кода, указанное параметром filename. Значение по умолчанию для filename указывает, что исходный код был объектом ST.Компиляция объекта ST может привести к исключениям, связанным с компиляцией; примером является
SyntaxError, вызванный деревом разбора дляdel f(0): эта инструкция считается законной в формальной грамматике Python, но не является законной конструкцией языка.SyntaxError, поднятый для этого условия, фактически генерируется компилятором байткода Python, поэтому он может быть поднят на этом этапе модулемparser. Большинство причин сбоя компиляции могут быть диагностированы программно путем проверки дерева разбора.
3. Запросы к объектам ST
Предоставлены две функции, которые позволяют приложению определить, был ли объект ST создан как выражение или набор инструкций. Ни одна из этих функций не может использоваться для определения того, был ли объект ST создан из исходного кода с помощью expr() или suite() или из дерева разбора с помощью sequence2st().
-
parser.isexpr(ast) -
Когда ast представляет собой форму
'eval', эта функция возвращает true, в противном случае возвращает false. Это полезно, так как объекты кода обычно нельзя запросить об этой информации с помощью существующих встроенных функций. Обратите внимание, что объекты кода, созданные с помощьюcompilest(), также нельзя запросить таким образом, и они идентичны тем, которые созданы встроенной функциейcompile().
-
parser.issuite(ast) -
Эта функция аналогична
isexpr()в том, что она сообщает, представляет ли объект ST форму'exec', обычно называемую «набором инструкций». Не следует полагать, что эта функция эквивалентнаnot isexpr(ast), так как в будущем могут быть добавлены дополнительные фрагменты синтаксиса.
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]) -
То же, что и
compilest(st, filename).
-
ST.isexpr() -
То же, что и
isexpr(st).
-
ST.issuite() -
То же, что и
issuite(st).
-
ST.tolist([line_info]) -
То же, что и
st2list(st, line_info).
-
ST.totuple([line_info]) -
То же, что и
st2tuple(st, line_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/2.7/library/parser.html