parser.md
1> **Источник:** https://python-all.ru/3.3/library/parser.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 31.1. [`parser`](https://python-all.ru/3.3/library/parser.html#module-parser) – Доступ к деревьям разбора Python89Модуль [`parser`](https://python-all.ru/3.3/library/parser.html#module-parser) предоставляет интерфейс к внутреннему парсеру и байт-код компилятору Python. Основное назначение этого интерфейса – позволить коду Python редактировать дерево разбора выражения Python и создавать из него исполняемый код. Это лучше, чем пытаться разобрать и изменить произвольный фрагмент кода Python как строку, потому что разбор выполняется точно так же, как и для кода, составляющего приложение. К тому же это быстрее.1011> **Примечание**12>13> Начиная с Python 2.5 гораздо удобнее внедряться на этапе генерации и компиляции абстрактного синтаксического дерева (AST), используя модуль [`ast`](https://python-all.ru/3.3/library/ast.html#module-ast).1415Об этом модуле важно знать несколько вещей, чтобы правильно работать с создаваемыми структурами данных. Это не учебник по редактированию деревьев разбора кода Python, но здесь приведены некоторые примеры использования модуля [`parser`](https://python-all.ru/3.3/library/parser.html#module-parser).1617Самое главное – требуется хорошее понимание грамматики Python, которую обрабатывает внутренний парсер. Полную информацию о синтаксисе языка можно найти в [*Справочнике по языку Python*](https://python-all.ru/3.3/reference/index.html#reference-index). Сам парсер создаётся по спецификации грамматики, определённой в файле `Grammar/Grammar` в стандартной поставке Python. Деревья разбора, хранящиеся в объектах ST, создаваемых этим модулем, – это фактический результат работы внутреннего парсера при вызове функций [`expr()`](https://python-all.ru/3.3/library/parser.html#parser.expr) или [`suite()`](https://python-all.ru/3.3/library/parser.html#parser.suite), описанных ниже. Объекты ST, созданные функцией [`sequence2st()`](https://python-all.ru/3.3/library/parser.html#parser.sequence2st), точно воспроизводят эти структуры. Имейте в виду, что значения последовательностей, считающиеся «правильными», могут меняться от версии Python к версии по мере изменения формальной грамматики языка. Однако перенос кода из одной версии Python в другую в виде исходного текста всегда позволит создать правильные деревья разбора в целевой версии, с единственным ограничением: при переходе на более старую версию интерпретатора более новые языковые конструкции не поддерживаются. Деревья разбора обычно не совместимы между версиями, тогда как исходный код всегда был совместим вперёд.1819Каждый элемент последовательностей, возвращаемых [`st2list()`](https://python-all.ru/3.3/library/parser.html#parser.st2list) или [`st2tuple()`](https://python-all.ru/3.3/library/parser.html#parser.st2tuple), имеет простую форму. Последовательности, представляющие нетерминальные элементы грамматики, всегда имеют длину больше единицы. Первый элемент – целое число, идентифицирующее продукцию в грамматике. Этим целым числам даны символьные имена в заголовочном файле C `Include/graminit.h` и в модуле Python [`symbol`](https://python-all.ru/3.3/library/symbol.html#module-symbol). Каждый дополнительный элемент последовательности представляет компонент продукции, распознанный во входной строке: это всегда последовательности, имеющие ту же форму, что и родительская. Важная особенность этой структуры, которую следует отметить: ключевые слова, используемые для идентификации типа родительского узла, например ключевое слово [`if`](https://python-all.ru/3.3/reference/compound_stmts.html#if) в `if_stmt`, включаются в дерево узлов без какой-либо специальной обработки. Например, ключевое слово [`if`](https://python-all.ru/3.3/reference/compound_stmts.html#if) представлено кортежем `(1, 'if')`, где `1` – числовое значение, связанное со всеми токенами `NAME`, включая имена переменных и функций, определённые пользователем. В альтернативной форме, возвращаемой при запросе информации о номерах строк, тот же токен может быть представлен как `(1, 'if', 12)`, где `12` обозначает номер строки, в которой был найден терминальный символ.2021Терминальные элементы представлены почти так же, но без дочерних элементов и с добавлением исходного текста, который был распознан. Пример ключевого слова [`if`](https://python-all.ru/3.3/reference/compound_stmts.html#if) выше показателен. Различные типы терминальных символов определены в заголовочном файле C `Include/token.h` и в модуле Python [`token`](https://python-all.ru/3.3/library/token.html#module-token).2223ST-объекты не обязательны для поддержки функциональности этого модуля, но предоставляются для трёх целей: позволить приложению распределить затраты на обработку сложных деревьев разбора, предоставить представление дерева разбора, экономящее память по сравнению с представлением в виде списков или кортежей Python, и облегчить создание дополнительных модулей на C, работающих с деревьями разбора. В Python можно создать простой класс-«обёртку», чтобы скрыть использование ST-объектов.2425Модуль [`parser`](https://python-all.ru/3.3/library/parser.html#module-parser) определяет функции для нескольких различных целей. Самые важные – создание объектов ST и преобразование объектов ST в другие представления, такие как деревья разбора и скомпилированные объекты кода, но также есть функции, которые служат для определения типа дерева разбора, представленного объектом ST.2627> **См. также**28>29> **Модуль [`symbol`](https://python-all.ru/3.3/library/symbol.html#module-symbol)**30>31> Полезные константы, представляющие внутренние узлы дерева разбора.32>33> **Модуль [`token`](https://python-all.ru/3.3/library/token.html#module-token)**34>35> Полезные константы, представляющие листовые узлы дерева разбора, и функции для проверки значений узлов.3637## 31.1.1. Создание объектов ST3839Объекты ST могут быть созданы из исходного кода или из дерева разбора. При создании объекта ST из исходного кода используются разные функции для создания форм `'eval'` и `'exec'`.4041#### `parser.expr(source)`4243Функция [`expr()`](https://python-all.ru/3.3/library/parser.html#parser.expr) разбирает параметр *source* так, как если бы он был передан в `compile(source, 'file.py', 'eval')`. Если разбор успешен, создаётся объект ST, содержащий внутреннее представление дерева разбора; в противном случае возбуждается соответствующее исключение.4445#### `parser.suite(source)`4647Функция [`suite()`](https://python-all.ru/3.3/library/parser.html#parser.suite) разбирает параметр *source* так, как если бы он был передан в `compile(source, 'file.py', 'exec')`. Если разбор успешен, создаётся объект ST, содержащий внутреннее представление дерева разбора; в противном случае возбуждается соответствующее исключение.4849#### `parser.sequence2st(sequence)`5051Эта функция принимает дерево разбора, представленное в виде последовательности, и строит внутреннее представление, если это возможно. Если она может проверить, что дерево соответствует грамматике Python и все узлы имеют допустимые типы узлов в текущей версии Python, создаётся объект ST из внутреннего представления и возвращается вызывающему. Если возникают проблемы при создании внутреннего представления или дерево не проходит проверку, возбуждается исключение [`ParserError`](https://python-all.ru/3.3/library/parser.html#parser.ParserError). Не следует предполагать, что объект ST, созданный таким образом, скомпилируется правильно; обычные исключения, возникающие при компиляции, всё ещё могут быть вызваны, когда объект ST передаётся [`compilest()`](https://python-all.ru/3.3/library/parser.html#parser.compilest). Это может указывать на проблемы, не связанные с синтаксисом (например, исключение [`MemoryError`](https://python-all.ru/3.3/library/exceptions.html#MemoryError)), но также может быть связано с такими конструкциями, как результат разбора `del f(0)`, который проходит парсер Python, но проверяется компилятором байт-кода.5253Последовательности, представляющие терминальные токены, могут быть представлены либо как двухэлементные списки вида `(1, 'name')`, либо как трёхэлементные списки вида `(1, 'name', 56)`. Если присутствует третий элемент, он считается допустимым номером строки. Номер строки может быть указан для любого подмножества терминальных символов во входном дереве.5455#### `parser.tuple2st(sequence)`5657Это та же функция, что и [`sequence2st()`](https://python-all.ru/3.3/library/parser.html#parser.sequence2st). Эта точка входа сохранена для обратной совместимости.5859## 31.1.2. Преобразование объектов ST6061ST-объекты, независимо от входных данных, использованных для их создания, могут быть преобразованы в деревья разбора, представленные в виде списков или кортежей, или скомпилированы в исполняемые объекты кода. Деревья разбора могут быть извлечены с информацией о номерах строк или без неё.6263#### `parser.st2list(st, line_info=False, col_info=False)`6465Эта функция принимает объект ST от вызывающего в параметре *st* и возвращает список Python, представляющий эквивалентное дерево разбора. Полученное представление в виде списка можно использовать для просмотра или создания нового дерева разбора в форме списка. Эта функция не завершается ошибкой, пока есть достаточно памяти для построения спискового представления. Если дерево разбора будет использоваться только для просмотра, следует использовать [`st2tuple()`](https://python-all.ru/3.3/library/parser.html#parser.st2tuple), чтобы уменьшить потребление памяти и фрагментацию. Когда требуется представление в виде списка, эта функция значительно быстрее, чем получение кортежного представления и его преобразование во вложенные списки.6667Если *line\_info* равен true, для всех терминальных токенов будет включена информация о номере строки в качестве третьего элемента списка, представляющего токен. Обратите внимание, что указанный номер строки определяет строку, в которой токен *заканчивается*. Эта информация опускается, если флаг равен false или опущен.6869#### `parser.st2tuple(st, line_info=False, col_info=False)`7071Эта функция принимает объект ST от вызывающего в параметре *st* и возвращает кортеж Python, представляющий эквивалентное дерево разбора. За исключением того, что возвращается кортеж вместо списка, эта функция идентична [`st2list()`](https://python-all.ru/3.3/library/parser.html#parser.st2list).7273Если *line\_info* равен true, для всех терминальных токенов будет включена информация о номере строки в качестве третьего элемента списка, представляющего токен. Эта информация опускается, если флаг равен false или опущен.7475#### `parser.compilest(st, filename='<syntax-tree>')`7677Компилятор байт-кода Python может быть вызван для объекта ST, чтобы получить объекты кода, которые можно использовать как часть вызова встроенных функций [`exec()`](https://python-all.ru/3.3/library/functions.html#exec) или [`eval()`](https://python-all.ru/3.3/library/functions.html#eval). Эта функция предоставляет интерфейс к компилятору, передавая внутреннее дерево разбора из *st* парсеру, используя имя исходного файла, заданное параметром *filename*. Значение по умолчанию для *filename* указывает, что исходный код был объектом ST.7879Компиляция объекта ST может привести к исключениям, связанным с компиляцией; примером может служить [`SyntaxError`](https://python-all.ru/3.3/library/exceptions.html#SyntaxError), вызванный деревом разбора для `del f(0)`: этот оператор считается допустимым в формальной грамматике Python, но не является допустимой языковой конструкцией. Исключение [`SyntaxError`](https://python-all.ru/3.3/library/exceptions.html#SyntaxError), возбуждаемое в этом случае, на самом деле генерируется обычным компилятором байт-кода Python, поэтому оно может быть возбуждено на этом этапе модулем [`parser`](https://python-all.ru/3.3/library/parser.html#module-parser). Большинство причин неудачной компиляции можно диагностировать программно, просматривая дерево разбора.8081## 31.1.3. Запросы к объектам ST8283Предоставляются две функции, которые позволяют приложению определить, был ли объект ST создан как выражение или как набор инструкций. Ни одну из этих функций нельзя использовать для определения того, был ли объект ST создан из исходного кода с помощью [`expr()`](https://python-all.ru/3.3/library/parser.html#parser.expr) или [`suite()`](https://python-all.ru/3.3/library/parser.html#parser.suite), или из дерева разбора с помощью [`sequence2st()`](https://python-all.ru/3.3/library/parser.html#parser.sequence2st).8485#### `parser.isexpr(st)`8687Если *st* представляет форму `'eval'`, эта функция возвращает истину, в противном случае – ложь. Это полезно, поскольку объекты кода обычно нельзя запросить на эту информацию с помощью существующих встроенных функций. Обратите внимание, что объекты кода, созданные [`compilest()`](https://python-all.ru/3.3/library/parser.html#parser.compilest), также нельзя так запросить, и они идентичны объектам, созданным встроенной функцией [`compile()`](https://python-all.ru/3.3/library/functions.html#compile).8889#### `parser.issuite(st)`9091Эта функция аналогична [`isexpr()`](https://python-all.ru/3.3/library/parser.html#parser.isexpr) в том, что она сообщает, представляет ли объект ST форму `'exec'`, обычно называемую «набором». Не стоит считать, что эта функция эквивалентна `not isexpr(st)`, поскольку в будущем могут поддерживаться дополнительные синтаксические фрагменты.9293## 31.1.4. Исключения и обработка ошибок9495Модуль parser определяет одно исключение, но также может передавать другие встроенные исключения из других частей среды выполнения Python. Информацию об исключениях, которые может вызывать каждая функция, смотрите в её описании.9697#### `exception parser.ParserError`9899Исключение, возникающее при сбое в модуле parser. Обычно оно возникает при ошибках проверки, а не при встроенном [`SyntaxError`](https://python-all.ru/3.3/library/exceptions.html#SyntaxError), возбуждаемом во время обычного разбора. Аргумент исключения – это либо строка, описывающая причину сбоя, либо кортеж, содержащий последовательность, вызывающую сбой, из дерева разбора, переданного в [`sequence2st()`](https://python-all.ru/3.3/library/parser.html#parser.sequence2st), и пояснительную строку. Вызовы [`sequence2st()`](https://python-all.ru/3.3/library/parser.html#parser.sequence2st) должны уметь обрабатывать оба типа исключений, в то время как вызовам других функций модуля достаточно знать только простые строковые значения.100101Обратите внимание, что функции [`compilest()`](https://python-all.ru/3.3/library/parser.html#parser.compilest), [`expr()`](https://python-all.ru/3.3/library/parser.html#parser.expr) и [`suite()`](https://python-all.ru/3.3/library/parser.html#parser.suite) могут вызывать исключения, которые обычно возбуждаются процессами разбора и компиляции. К ним относятся встроенные исключения [`MemoryError`](https://python-all.ru/3.3/library/exceptions.html#MemoryError), [`OverflowError`](https://python-all.ru/3.3/library/exceptions.html#OverflowError), [`SyntaxError`](https://python-all.ru/3.3/library/exceptions.html#SyntaxError) и [`SystemError`](https://python-all.ru/3.3/library/exceptions.html#SystemError). В этих случаях такие исключения несут всю обычную смысловую нагрузку. Подробную информацию см. в описаниях каждой функции.102103## 31.1.5. Объекты ST104105Между объектами ST поддерживаются сравнения на порядок и равенство. Также поддерживается сериализация объектов ST с помощью модуля [`pickle`](https://python-all.ru/3.3/library/pickle.html#module-pickle).106107#### `parser.STType`108109Тип объектов, возвращаемых функциями [`expr()`](https://python-all.ru/3.3/library/parser.html#parser.expr), [`suite()`](https://python-all.ru/3.3/library/parser.html#parser.suite) и [`sequence2st()`](https://python-all.ru/3.3/library/parser.html#parser.sequence2st).110111Объекты ST имеют следующие методы:112113#### `ST.compile(filename='<syntax-tree>')`114115То же, что и `compilest(st, filename)`.116117#### `ST.isexpr()`118119То же, что и `isexpr(st)`.120121#### `ST.issuite()`122123То же, что и `issuite(st)`.124125#### `ST.tolist(line_info=False, col_info=False)`126127То же, что и `st2list(st, line_info, col_info)`.128129#### `ST.totuple(line_info=False, col_info=False)`130131То же, что и `st2tuple(st, line_info, col_info)`.132133## 31.1.6. Пример: эмуляция [`compile()`](https://python-all.ru/3.3/library/functions.html#compile)134135Хотя между разбором и генерацией байт-кода может выполняться множество полезных операций, самая простая – ничего не делать. Для этого использование модуля [`parser`](https://python-all.ru/3.3/library/parser.html#module-parser) для создания промежуточной структуры данных эквивалентно следующему коду136137```python138>>> code = compile('a + 5', 'file.py', 'eval')139>>> a = 5140>>> eval(code)14110142```143144Эквивалентная операция с использованием модуля [`parser`](https://python-all.ru/3.3/library/parser.html#module-parser) несколько длиннее и позволяет сохранить промежуточное внутреннее дерево разбора в виде объекта ST:145146```python147>>> import parser148>>> st = parser.expr('a + 5')149>>> code = st.compile('file.py')150>>> a = 5151>>> eval(code)15210153```154155Приложение, которому нужны как объекты ST, так и объекты кода, может упаковать этот код в готовые функции:156157```python158import parser159160def load_suite(source_string):161 st = parser.suite(source_string)162 return st, st.compile()163164def load_expression(source_string):165 st = parser.expr(source_string)166 return st, st.compile()167```168