ast.md
1> **Источник:** https://python-all.ru/3.4/library/ast.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 32.2. [`ast`](https://python-all.ru/3.4/library/ast.html#module-ast) – Абстрактные синтаксические деревья89**Исходный код:** [Lib/ast.py](https://python-all.ru/src/3.4/Lib/ast.py)1011---1213Модуль [`ast`](https://python-all.ru/3.4/library/ast.html#module-ast) помогает приложениям Python обрабатывать деревья абстрактного синтаксиса Python. Абстрактный синтаксис может меняться от версии к версии; этот модуль позволяет программно узнавать, как выглядит текущая грамматика.1415Абстрактное синтаксическое дерево можно получить, передав `ast.PyCF_ONLY_AST` в качестве флага встроенной функции [`compile()`](https://python-all.ru/3.4/library/functions.html#compile) или воспользовавшись вспомогательной функцией [`parse()`](https://python-all.ru/3.4/library/ast.html#ast.parse), предоставленной в этом модуле. Результатом будет дерево объектов, классы которых наследуют от [`ast.AST`](https://python-all.ru/3.4/library/ast.html#ast.AST). Абстрактное синтаксическое дерево можно скомпилировать в объект кода Python с помощью встроенной функции [`compile()`](https://python-all.ru/3.4/library/functions.html#compile).1617## 32.2.1. Классы узлов1819#### `class ast.AST`2021Это базовый класс для всех узлов AST. Конкретные классы узлов определяются из файла `Parser/Python.asdl`, который воспроизведён [*ниже*](https://python-all.ru/3.4/library/ast.html#abstract-grammar). Они определены в C-модуле `_ast` и реэкспортируются в [`ast`](https://python-all.ru/3.4/library/ast.html#module-ast).2223Для каждого символа левой части абстрактной грамматики определён один класс (например, `ast.stmt` или `ast.expr`). Кроме того, для каждого конструктора правой части определён один класс; эти классы наследуют от классов левой части. Например, `ast.BinOp` наследует от `ast.expr`. Для правил вывода с альтернативами (так называемых «сумм») класс левой части является абстрактным: создаются только экземпляры конкретных конструкторных узлов.2425#### `_fields`2627Каждый конкретный класс имеет атрибут [`_fields`](https://python-all.ru/3.4/library/ast.html#ast.AST._fields), который содержит имена всех дочерних узлов.2829Каждый экземпляр конкретного класса имеет по одному атрибуту для каждого дочернего узла, тип которого определён грамматикой. Например, экземпляры `ast.BinOp` имеют атрибут `left` типа `ast.expr`.3031Если эти атрибуты помечены как необязательные в грамматике (с помощью вопросительного знака), их значением может быть `None`. Если атрибуты могут иметь ноль или более значений (помечены звёздочкой), значения представляются в виде списков Python. Все возможные атрибуты должны присутствовать и иметь допустимые значения при компиляции AST с помощью [`compile()`](https://python-all.ru/3.4/library/functions.html#compile).3233#### `lineno`3435#### `col_offset`3637Экземпляры подклассов `ast.expr` и `ast.stmt` имеют атрибуты [`lineno`](https://python-all.ru/3.4/library/ast.html#ast.AST.lineno) и [`col_offset`](https://python-all.ru/3.4/library/ast.html#ast.AST.col_offset). [`lineno`](https://python-all.ru/3.4/library/ast.html#ast.AST.lineno) – это номер строки исходного текста (нумерация с 1, так что первая строка – строка 1), а [`col_offset`](https://python-all.ru/3.4/library/ast.html#ast.AST.col_offset) – это смещение в байтах UTF-8 первого токена, породившего узел. Смещение в UTF-8 записывается, потому что парсер использует UTF-8 внутри.3839Конструктор класса `ast.T` разбирает свои аргументы следующим образом:4041- Если есть позиционные аргументы, их должно быть столько же, сколько элементов в `T._fields`; они будут присвоены как атрибуты с этими именами.42- Если есть ключевые аргументы, они установят атрибуты с теми же именами в указанные значения.4344Например, чтобы создать и заполнить узел `ast.UnaryOp`, можно использовать4546```python47node = ast.UnaryOp()48node.op = ast.USub()49node.operand = ast.Num()50node.operand.n = 551node.operand.lineno = 052node.operand.col_offset = 053node.lineno = 054node.col_offset = 055```5657или более компактный5859```python60node = ast.UnaryOp(ast.USub(), ast.Num(5, lineno=0, col_offset=0),61 lineno=0, col_offset=0)62```6364## 32.2.2. Абстрактная грамматика6566Абстрактная грамматика в настоящее время определяется следующим образом:6768```python69-- ASDL's six builtin types are identifier, int, string, bytes, object, singleton7071module Python72{73 mod = Module(stmt* body)74 | Interactive(stmt* body)75 | Expression(expr body)7677 -- not really an actual node but useful in Jython's typesystem.78 | Suite(stmt* body)7980 stmt = FunctionDef(identifier name, arguments args, 81 stmt* body, expr* decorator_list, expr? returns)82 | ClassDef(identifier name, 83 expr* bases,84 keyword* keywords,85 expr? starargs,86 expr? kwargs,87 stmt* body,88 expr* decorator_list)89 | Return(expr? value)9091 | Delete(expr* targets)92 | Assign(expr* targets, expr value)93 | AugAssign(expr target, operator op, expr value)9495 -- use 'orelse' because else is a keyword in target languages96 | For(expr target, expr iter, stmt* body, stmt* orelse)97 | While(expr test, stmt* body, stmt* orelse)98 | If(expr test, stmt* body, stmt* orelse)99 | With(withitem* items, stmt* body)100101 | Raise(expr? exc, expr? cause)102 | Try(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody)103 | Assert(expr test, expr? msg)104105 | Import(alias* names)106 | ImportFrom(identifier? module, alias* names, int? level)107108 | Global(identifier* names)109 | Nonlocal(identifier* names)110 | Expr(expr value)111 | Pass | Break | Continue112113 -- XXX Jython will be different114 -- col_offset is the byte offset in the utf8 string the parser uses115 attributes (int lineno, int col_offset)116117 -- BoolOp() can use left & right?118 expr = BoolOp(boolop op, expr* values)119 | BinOp(expr left, operator op, expr right)120 | UnaryOp(unaryop op, expr operand)121 | Lambda(arguments args, expr body)122 | IfExp(expr test, expr body, expr orelse)123 | Dict(expr* keys, expr* values)124 | Set(expr* elts)125 | ListComp(expr elt, comprehension* generators)126 | SetComp(expr elt, comprehension* generators)127 | DictComp(expr key, expr value, comprehension* generators)128 | GeneratorExp(expr elt, comprehension* generators)129 -- the grammar constrains where yield expressions can occur130 | Yield(expr? value)131 | YieldFrom(expr value)132 -- need sequences for compare to distinguish between133 -- x < 4 < 3 and (x < 4) < 3134 | Compare(expr left, cmpop* ops, expr* comparators)135 | Call(expr func, expr* args, keyword* keywords,136 expr? starargs, expr? kwargs)137 | Num(object n) -- a number as a PyObject.138 | Str(string s) -- need to specify raw, unicode, etc?139 | Bytes(bytes s)140 | NameConstant(singleton value)141 | Ellipsis142143 -- the following expression can appear in assignment context144 | Attribute(expr value, identifier attr, expr_context ctx)145 | Subscript(expr value, slice slice, expr_context ctx)146 | Starred(expr value, expr_context ctx)147 | Name(identifier id, expr_context ctx)148 | List(expr* elts, expr_context ctx) 149 | Tuple(expr* elts, expr_context ctx)150151 -- col_offset is the byte offset in the utf8 string the parser uses152 attributes (int lineno, int col_offset)153154 expr_context = Load | Store | Del | AugLoad | AugStore | Param155156 slice = Slice(expr? lower, expr? upper, expr? step) 157 | ExtSlice(slice* dims) 158 | Index(expr value) 159160 boolop = And | Or 161162 operator = Add | Sub | Mult | Div | Mod | Pow | LShift 163 | RShift | BitOr | BitXor | BitAnd | FloorDiv164165 unaryop = Invert | Not | UAdd | USub166167 cmpop = Eq | NotEq | Lt | LtE | Gt | GtE | Is | IsNot | In | NotIn168169 comprehension = (expr target, expr iter, expr* ifs)170171 excepthandler = ExceptHandler(expr? type, identifier? name, stmt* body)172 attributes (int lineno, int col_offset)173174 arguments = (arg* args, arg? vararg, arg* kwonlyargs, expr* kw_defaults,175 arg? kwarg, expr* defaults)176177 arg = (identifier arg, expr? annotation)178 attributes (int lineno, int col_offset)179180 -- keyword arguments supplied to call181 keyword = (identifier arg, expr value)182183 -- import name with optional 'as' alias.184 alias = (identifier name, identifier? asname)185186 withitem = (expr context_expr, expr? optional_vars)187}188```189190## 32.2.3. [`ast`](https://python-all.ru/3.4/library/ast.html#module-ast) Вспомогательные функции191192Помимо классов узлов, модуль [`ast`](https://python-all.ru/3.4/library/ast.html#module-ast) определяет следующие вспомогательные функции и классы для обхода абстрактных синтаксических деревьев:193194#### `ast.parse(source, filename='<unknown>', mode='exec')`195196Разбирает исходный код в узел AST. Эквивалентно `compile(source, filename, mode, ast.PyCF_ONLY_AST)`.197198#### `ast.literal_eval(node_or_string)`199200Безопасно вычисляет узел выражения или строку, содержащую литерал Python или отображение контейнера. Предоставленная строка или узел может состоять только из следующих структур литералов Python: строки, байтовые строки, числа, кортежи, списки, словари, множества, логические значения и `None`.201202Это можно использовать для безопасного вычисления строк, содержащих значения Python из ненадёжных источников, без необходимости разбирать значения самостоятельно. Он не способен вычислять произвольно сложные выражения, например с операторами или индексацией.203204Изменено в версии 3.2: Теперь допускает литералы байтов и множеств.205206#### `ast.get_docstring(node, clean=True)`207208Возвращает docstring заданного *node* (который должен быть узлом `FunctionDef`, `ClassDef` или `Module` ), или `None`, если docstring нет. Если *clean* равно True, очищает отступы docstring с помощью [`inspect.cleandoc()`](https://python-all.ru/3.4/library/inspect.html#inspect.cleandoc).209210#### `ast.fix_missing_locations(node)`211212При компиляции дерева узлов с помощью [`compile()`](https://python-all.ru/3.4/library/functions.html#compile) компилятор ожидает атрибуты `lineno` и `col_offset` для каждого узла, который их поддерживает. Заполнять их вручную для сгенерированных узлов довольно утомительно, поэтому эта вспомогательная функция рекурсивно добавляет эти атрибуты, если они ещё не установлены, присваивая им значения родительского узла. Она работает рекурсивно, начиная с *node*.213214#### `ast.increment_lineno(node, n=1)`215216Увеличить номер строки каждого узла в дереве, начиная с *node*, на *n*. Это полезно для «переноса кода» в другое место в файле.217218#### `ast.copy_location(new_node, old_node)`219220Копирует информацию о положении в исходном коде (`lineno` и `col_offset`) из *old\_node* в *new\_node*, если это возможно, и возвращает *new\_node*.221222#### `ast.iter_fields(node)`223224Генерирует кортеж `(fieldname, value)` для каждого поля из `node._fields`, которое присутствует в *node*.225226#### `ast.iter_child_nodes(node)`227228Генерирует все непосредственные дочерние узлы *node*, то есть все поля, являющиеся узлами, и все элементы полей, являющихся списками узлов.229230#### `ast.walk(node)`231232Рекурсивно генерирует все узлы-потомки в дереве, начиная с *node* (включая сам *node*), в произвольном порядке. Это полезно, если требуется только изменить узлы на месте, а контекст не важен.233234#### `class ast.NodeVisitor`235236Базовый класс для обхода абстрактного синтаксического дерева, который вызывает функцию посетителя для каждого найденного узла. Эта функция может возвращать значение, которое передаётся методом [`visit()`](https://python-all.ru/3.4/library/ast.html#ast.NodeVisitor.visit).237238Этот класс предназначен для наследования; в подклассе добавляются методы-посетители.239240#### `visit(node)`241242Посещает узел. Реализация по умолчанию вызывает метод `self.visit_classname`, где *classname* – это имя класса узла, или [`generic_visit()`](https://python-all.ru/3.4/library/ast.html#ast.NodeVisitor.generic_visit), если такой метод не существует.243244#### `generic_visit(node)`245246Этот обходчик вызывает [`visit()`](https://python-all.ru/3.4/library/ast.html#ast.NodeVisitor.visit) для всех дочерних узлов данного узла.247248Обратите внимание, что дочерние узлы узлов, для которых определён пользовательский метод обхода, не будут посещены, если обходчик не вызовет [`generic_visit()`](https://python-all.ru/3.4/library/ast.html#ast.NodeVisitor.generic_visit) или не посетит их самостоятельно.249250Не используйте [`NodeVisitor`](https://python-all.ru/3.4/library/ast.html#ast.NodeVisitor) для внесения изменений в узлы во время обхода. Для этого существует специальный обходчик ([`NodeTransformer`](https://python-all.ru/3.4/library/ast.html#ast.NodeTransformer)), позволяющий вносить изменения.251252#### `class ast.NodeTransformer`253254Подкласс [`NodeVisitor`](https://python-all.ru/3.4/library/ast.html#ast.NodeVisitor), который обходит абстрактное синтаксическое дерево и позволяет изменять узлы.255256[`NodeTransformer`](https://python-all.ru/3.4/library/ast.html#ast.NodeTransformer) обходит AST и использует возвращаемое значение методов обхода для замены или удаления старого узла. Если возвращаемое значение метода обхода равно `None`, узел удаляется из своего местоположения; в противном случае он заменяется возвращаемым значением. Возвращаемое значение может быть исходным узлом, и в этом случае замена не производится.257258Вот пример преобразователя, который заменяет все обращения к имени (`foo`) на `data['foo']`:259260```python261class RewriteName(NodeTransformer):262263 def visit_Name(self, node):264 return copy_location(Subscript(265 value=Name(id='data', ctx=Load()),266 slice=Index(value=Str(s=node.id)),267 ctx=node.ctx268 ), node)269```270271Имейте в виду, что если у узла, с которым вы работаете, есть дочерние узлы, вы должны либо преобразовать дочерние узлы самостоятельно, либо сначала вызвать метод `generic_visit()` для этого узла.272273Для узлов, входящих в состав набора инструкций (это относится ко всем узлам инструкций), посетитель может также возвращать список узлов, а не один узел.274275Обычно преобразователь используется следующим образом:276277```python278node = YourTransformer().visit(node)279```280281#### `ast.dump(node, annotate_fields=True, include_attributes=False)`282283Возвращает отформатированное представление дерева из узла *node*. В основном это полезно для отладки. Возвращаемая строка показывает имена и значения полей. Это делает код непригодным для вычисления, поэтому если требуется возможность вычисления, *annotate\_fields* должен быть установлен в `False`. Такие атрибуты, как номера строк и смещения столбцов, по умолчанию не выводятся. Если это нужно, *include\_attributes* можно установить в `True`.284285> **См. также**286>287> [Green Tree Snakes](https://python-all.ru/3.4/library/ast.html) – внешний ресурс документации, содержащий подробную информацию о работе с AST Python.288