ast.md
1> **Источник:** https://python-all.ru/2.7/library/ast.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 32.2. [`ast`](https://python-all.ru/2.7/library/ast.html#module-ast) – Абстрактные синтаксические деревья89Новое в версии 2.5: Низкоуровневый модуль `_ast`, содержащий только классы узлов.1011Новое в версии 2.6: Высокоуровневый модуль `ast`, содержащий все вспомогательные функции.1213**Исходный код:** [Lib/ast.py](https://python-all.ru/src/2.7/Lib/ast.py)1415---1617Модуль [`ast`](https://python-all.ru/2.7/library/ast.html#module-ast) помогает приложениям Python обрабатывать деревья абстрактного синтаксиса языка Python. Абстрактный синтаксис может меняться от версии к версии; с помощью этого модуля можно программно узнать, как выглядит текущая грамматика.1819Абстрактное синтаксическое дерево можно создать, передав `ast.PyCF_ONLY_AST` в качестве флага встроенной функции [`compile()`](https://python-all.ru/2.7/library/functions.html#compile) или используя вспомогательную функцию [`parse()`](https://python-all.ru/2.7/library/ast.html#ast.parse) из этого модуля. Результатом будет дерево объектов, классы которых наследуют от [`ast.AST`](https://python-all.ru/2.7/library/ast.html#ast.AST). Абстрактное синтаксическое дерево можно скомпилировать в объект кода Python с помощью встроенной функции [`compile()`](https://python-all.ru/2.7/library/functions.html#compile).2021## 32.2.1. Классы узлов2223#### `class ast.AST`2425Это базовый класс всех узлов AST. Конкретные классы узлов порождаются из файла `Parser/Python.asdl`, который воспроизведён [ниже](https://python-all.ru/2.7/library/ast.html#abstract-grammar). Они определены в C-модуле `_ast` и реэкспортированы в [`ast`](https://python-all.ru/2.7/library/ast.html#module-ast).2627Для каждого символа левой части абстрактной грамматики определён один класс (например, `ast.stmt` или `ast.expr`). Кроме того, для каждого конструктора правой части определён один класс; эти классы наследуют от классов для деревьев левой части. Например, `ast.BinOp` наследует от `ast.expr`. Для продукционных правил с альтернативами (так называемых «сумм») класс левой части является абстрактным: создаются только экземпляры конкретных узлов-конструкторов.2829#### `_fields`3031Каждый конкретный класс имеет атрибут [`_fields`](https://python-all.ru/2.7/library/ast.html#ast.AST._fields), который содержит имена всех дочерних узлов.3233Каждый экземпляр конкретного класса имеет по одному атрибуту для каждого дочернего узла, тип которого определён в грамматике. Например, экземпляры `ast.BinOp` имеют атрибут `left` типа `ast.expr`.3435Если эти атрибуты помечены как необязательные в грамматике (с помощью вопросительного знака), значением может быть `None`. Если атрибуты могут иметь ноль или более значений (помечены звёздочкой), значения представляются в виде списков Python. Все возможные атрибуты должны присутствовать и иметь корректные значения при компиляции AST с помощью [`compile()`](https://python-all.ru/2.7/library/functions.html#compile).3637#### `lineno`3839#### `col_offset`4041Экземпляры подклассов `ast.expr` и `ast.stmt` имеют [`lineno`](https://python-all.ru/2.7/library/ast.html#ast.AST.lineno) и [`col_offset`](https://python-all.ru/2.7/library/ast.html#ast.AST.col_offset) атрибуты. [`lineno`](https://python-all.ru/2.7/library/ast.html#ast.AST.lineno) – это номер строки исходного текста (нумерация с 1, то есть первая строка – строка 1), а [`col_offset`](https://python-all.ru/2.7/library/ast.html#ast.AST.col_offset) – смещение в байтах UTF-8 первого токена, который породил узел. Смещение в UTF-8 записывается, потому что синтаксический анализатор использует UTF-8 внутри.4243Конструктор класса `ast.T` разбирает свои аргументы следующим образом:4445- Если есть позиционные аргументы, их должно быть столько же, сколько элементов в `T._fields`; они будут присвоены как атрибуты с этими именами.46- Если есть ключевые аргументы, они установят атрибуты с теми же именами в указанные значения.4748Например, чтобы создать и заполнить узел `ast.UnaryOp`, можно использовать4950```python51node = ast.UnaryOp()52node.op = ast.USub()53node.operand = ast.Num()54node.operand.n = 555node.operand.lineno = 056node.operand.col_offset = 057node.lineno = 058node.col_offset = 059```6061или более компактный6263```python64node = ast.UnaryOp(ast.USub(), ast.Num(5, lineno=0, col_offset=0),65 lineno=0, col_offset=0)66```6768Новое в версии 2.6: Конструктор, описанный выше, был добавлен. В Python 2.5 узлы должны были создаваться вызовом конструктора класса без аргументов и последующей установкой атрибутов.6970## 32.2.2. Абстрактная грамматика7172Модуль определяет строковую константу `__version__`, которая является десятичным номером ревизии Subversion файла, показанного ниже.7374Абстрактная грамматика в настоящее время определяется следующим образом:7576```text77-- ASDL's five builtin types are identifier, int, string, object, bool7879module Python version "$Revision$"80{81 mod = Module(stmt* body)82 | Interactive(stmt* body)83 | Expression(expr body)8485 -- not really an actual node but useful in Jython's typesystem.86 | Suite(stmt* body)8788 stmt = FunctionDef(identifier name, arguments args, 89 stmt* body, expr* decorator_list)90 | ClassDef(identifier name, expr* bases, stmt* body, expr* decorator_list)91 | Return(expr? value)9293 | Delete(expr* targets)94 | Assign(expr* targets, expr value)95 | AugAssign(expr target, operator op, expr value)9697 -- not sure if bool is allowed, can always use int98 | Print(expr? dest, expr* values, bool nl)99100 -- use 'orelse' because else is a keyword in target languages101 | For(expr target, expr iter, stmt* body, stmt* orelse)102 | While(expr test, stmt* body, stmt* orelse)103 | If(expr test, stmt* body, stmt* orelse)104 | With(expr context_expr, expr? optional_vars, stmt* body)105106 -- 'type' is a bad name107 | Raise(expr? type, expr? inst, expr? tback)108 | TryExcept(stmt* body, excepthandler* handlers, stmt* orelse)109 | TryFinally(stmt* body, stmt* finalbody)110 | Assert(expr test, expr? msg)111112 | Import(alias* names)113 | ImportFrom(identifier? module, alias* names, int? level)114115 -- Doesn't capture requirement that locals must be116 -- defined if globals is117 -- still supports use as a function!118 | Exec(expr body, expr? globals, expr? locals)119120 | Global(identifier* names)121 | Expr(expr value)122 | Pass | Break | Continue123124 -- XXX Jython will be different125 -- col_offset is the byte offset in the utf8 string the parser uses126 attributes (int lineno, int col_offset)127128 -- BoolOp() can use left & right?129 expr = BoolOp(boolop op, expr* values)130 | BinOp(expr left, operator op, expr right)131 | UnaryOp(unaryop op, expr operand)132 | Lambda(arguments args, expr body)133 | IfExp(expr test, expr body, expr orelse)134 | Dict(expr* keys, expr* values)135 | Set(expr* elts)136 | ListComp(expr elt, comprehension* generators)137 | SetComp(expr elt, comprehension* generators)138 | DictComp(expr key, expr value, comprehension* generators)139 | GeneratorExp(expr elt, comprehension* generators)140 -- the grammar constrains where yield expressions can occur141 | Yield(expr? value)142 -- need sequences for compare to distinguish between143 -- x < 4 < 3 and (x < 4) < 3144 | Compare(expr left, cmpop* ops, expr* comparators)145 | Call(expr func, expr* args, keyword* keywords,146 expr? starargs, expr? kwargs)147 | Repr(expr value)148 | Num(object n) -- a number as a PyObject.149 | Str(string s) -- need to specify raw, unicode, etc?150 -- other literals? bools?151152 -- the following expression can appear in assignment context153 | Attribute(expr value, identifier attr, expr_context ctx)154 | Subscript(expr value, slice slice, expr_context ctx)155 | Name(identifier id, expr_context ctx)156 | List(expr* elts, expr_context ctx) 157 | Tuple(expr* elts, expr_context ctx)158159 -- col_offset is the byte offset in the utf8 string the parser uses160 attributes (int lineno, int col_offset)161162 expr_context = Load | Store | Del | AugLoad | AugStore | Param163164 slice = Ellipsis | Slice(expr? lower, expr? upper, expr? step) 165 | ExtSlice(slice* dims) 166 | Index(expr value) 167168 boolop = And | Or 169170 operator = Add | Sub | Mult | Div | Mod | Pow | LShift 171 | RShift | BitOr | BitXor | BitAnd | FloorDiv172173 unaryop = Invert | Not | UAdd | USub174175 cmpop = Eq | NotEq | Lt | LtE | Gt | GtE | Is | IsNot | In | NotIn176177 comprehension = (expr target, expr iter, expr* ifs)178179 -- not sure what to call the first argument for raise and except180 excepthandler = ExceptHandler(expr? type, expr? name, stmt* body)181 attributes (int lineno, int col_offset)182183 arguments = (expr* args, identifier? vararg, 184 identifier? kwarg, expr* defaults)185186 -- keyword arguments supplied to call187 keyword = (identifier arg, expr value)188189 -- import name with optional 'as' alias.190 alias = (identifier name, identifier? asname)191}192```193194## 32.2.3. [`ast`](https://python-all.ru/2.7/library/ast.html#module-ast) Вспомогательные функции195196Новое в версии 2.6.197198Помимо классов узлов, модуль [`ast`](https://python-all.ru/2.7/library/ast.html#module-ast) определяет следующие вспомогательные функции и классы для обхода абстрактных синтаксических деревьев:199200#### `ast.parse(source, filename='<unknown>', mode='exec')`201202Разбирает исходный код в узел AST. Эквивалентно `compile(source, filename, mode, ast.PyCF_ONLY_AST)`.203204> **Предупреждение**205>206> Можно вызвать сбой интерпретатора Python с помощью достаточно большой/сложной строки из-за ограничений глубины стека в компиляторе AST Python.207208#### `ast.literal_eval(node_or_string)`209210Безопасно вычисляет узел выражения или строку в кодировке Unicode или *Latin-1*, содержащую литерал Python или отображение контейнера. Предоставленная строка или узел может содержать только следующие литеральные структуры Python: строки, числа, кортежи, списки, словари, булевы значения и `None`.211212Это можно использовать для безопасного вычисления строк, содержащих значения Python из ненадёжных источников, без необходимости разбирать значения самостоятельно. Он не способен вычислять произвольно сложные выражения, например с операторами или индексацией.213214> **Предупреждение**215>216> Можно вызвать сбой интерпретатора Python с помощью достаточно большой/сложной строки из-за ограничений глубины стека в компиляторе AST Python.217218#### `ast.get_docstring(node, clean=True)`219220Возвращает докстринг заданного узла *node* (который должен быть узлом `FunctionDef`, `ClassDef` или `Module`), или `None` если у него нет докстринга. Если *clean* истинно, очищает отступы докстринга с помощью [`inspect.cleandoc()`](https://python-all.ru/2.7/library/inspect.html#inspect.cleandoc).221222#### `ast.fix_missing_locations(node)`223224При компиляции дерева узлов с помощью [`compile()`](https://python-all.ru/2.7/library/functions.html#compile) компилятор ожидает атрибуты `lineno` и `col_offset` для каждого узла, который их поддерживает. Заполнять их вручную для сгенерированных узлов довольно утомительно, поэтому эта вспомогательная функция рекурсивно добавляет эти атрибуты, если их ещё нет, устанавливая их равными значениям родительского узла. Работает рекурсивно, начиная с *node*.225226#### `ast.increment_lineno(node, n=1)`227228Увеличить номер строки каждого узла в дереве, начиная с *node*, на *n*. Это полезно для «переноса кода» в другое место в файле.229230#### `ast.copy_location(new_node, old_node)`231232Скопировать местоположение в исходном коде (`lineno` и `col_offset`) из *old\_node* в *new\_node*, если возможно, и вернуть *new\_node*.233234#### `ast.iter_fields(node)`235236Генерирует кортеж из `(fieldname, value)` для каждого поля в `node._fields`, которое присутствует в *node*.237238#### `ast.iter_child_nodes(node)`239240Генерирует все непосредственные дочерние узлы *node*, то есть все поля, являющиеся узлами, и все элементы полей, являющихся списками узлов.241242#### `ast.walk(node)`243244Рекурсивно генерирует все узлы-потомки в дереве, начиная с *node* (включая сам *node*), в произвольном порядке. Это полезно, если требуется только изменить узлы на месте, а контекст не важен.245246#### `class ast.NodeVisitor`247248Базовый класс для обхода узлов, который обходит абстрактное синтаксическое дерево и вызывает функцию-посетитель для каждого найденного узла. Эта функция может вернуть значение, которое передаётся методом [`visit()`](https://python-all.ru/2.7/library/ast.html#ast.NodeVisitor.visit).249250Этот класс предназначен для наследования; в подклассе добавляются методы-посетители.251252#### `visit(node)`253254Посещает узел. Реализация по умолчанию вызывает метод `self.visit_classname`, где *classname* – имя класса узла, или [`generic_visit()`](https://python-all.ru/2.7/library/ast.html#ast.NodeVisitor.generic_visit), если такой метод отсутствует.255256#### `generic_visit(node)`257258Этот посетитель вызывает [`visit()`](https://python-all.ru/2.7/library/ast.html#ast.NodeVisitor.visit) для всех дочерних узлов.259260Обратите внимание, что дочерние узлы тех узлов, для которых определён собственный метод-посетитель, не будут посещены, если посетитель сам не вызовет [`generic_visit()`](https://python-all.ru/2.7/library/ast.html#ast.NodeVisitor.generic_visit) или не обойдёт их самостоятельно.261262Не используйте [`NodeVisitor`](https://python-all.ru/2.7/library/ast.html#ast.NodeVisitor), если требуется вносить изменения в узлы во время обхода. Для этого существует специальный посетитель ([`NodeTransformer`](https://python-all.ru/2.7/library/ast.html#ast.NodeTransformer)), который допускает модификации.263264#### `class ast.NodeTransformer`265266Подкласс [`NodeVisitor`](https://python-all.ru/2.7/library/ast.html#ast.NodeVisitor), который обходит абстрактное синтаксическое дерево и позволяет изменять узлы.267268Метод [`NodeTransformer`](https://python-all.ru/2.7/library/ast.html#ast.NodeTransformer) обходит AST и использует возвращаемое значение методов-посетителей для замены или удаления старого узла. Если возвращаемое значение метода-посетителя равно `None`, узел будет удалён из своего местоположения; в противном случае он заменяется возвращённым значением. Возвращённое значение может быть исходным узлом – в этом случае замена не происходит.269270Вот пример преобразователя, который переписывает все обращения к именам (`foo`) в `data['foo']`:271272```python273class RewriteName(NodeTransformer):274275 def visit_Name(self, node):276 return copy_location(Subscript(277 value=Name(id='data', ctx=Load()),278 slice=Index(value=Str(s=node.id)),279 ctx=node.ctx280 ), node)281```282283Имейте в виду: если у узла, с которым вы работаете, есть дочерние узлы, необходимо либо преобразовать дочерние узлы самостоятельно, либо сначала вызвать для узла метод `generic_visit()`.284285Для узлов, входящих в состав набора инструкций (это относится ко всем узлам инструкций), посетитель может также возвращать список узлов, а не один узел.286287Обычно преобразователь используется следующим образом:288289```python290node = YourTransformer().visit(node)291```292293#### `ast.dump(node, annotate_fields=True, include_attributes=False)`294295Возвращает форматированный дамп дерева в узле *node*. Это в основном полезно для целей отладки. Возвращаемая строка показывает имена и значения полей. Это делает код невычислимым, поэтому если требуется вычисление, *annotate\_fields* должно быть установлено в `False`. Атрибуты, такие как номера строк и смещения столбцов, по умолчанию не дампятся. Если это требуется, *include\_attributes* может быть установлено в `True`.296