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

ast.md

285 строк · 20.0 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3.2/library/ast.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 30.2. [`ast`](https://python-all.ru/3.2/library/ast.html#module-ast) – Абстрактные синтаксические деревья89**Исходный код:** [Lib/ast.py](https://python-all.ru/src/3.2/Lib/ast.py)1011---1213Модуль [`ast`](https://python-all.ru/3.2/library/ast.html#module-ast) помогает приложениям Python обрабатывать деревья абстрактного синтаксиса Python. Абстрактный синтаксис может меняться от версии к версии; этот модуль позволяет программно узнавать, как выглядит текущая грамматика.1415Абстрактное синтаксическое дерево можно получить, передав `ast.PyCF_ONLY_AST` в качестве флага встроенной функции [`compile()`](https://python-all.ru/3.2/library/functions.html#compile) или воспользовавшись вспомогательной функцией [`parse()`](https://python-all.ru/3.2/library/ast.html#ast.parse), предоставленной в этом модуле. Результатом будет дерево объектов, классы которых наследуют от [`ast.AST`](https://python-all.ru/3.2/library/ast.html#ast.AST). Абстрактное синтаксическое дерево можно скомпилировать в объект кода Python с помощью встроенной функции [`compile()`](https://python-all.ru/3.2/library/functions.html#compile).1617## 30.2.1. Классы узлов1819#### `class ast.AST`2021Это базовый класс для всех узлов AST. Конкретные классы узлов определяются из файла `Parser/Python.asdl`, который воспроизведён [*ниже*](https://python-all.ru/3.2/library/ast.html#abstract-grammar). Они определены в C-модуле `_ast` и реэкспортируются в [`ast`](https://python-all.ru/3.2/library/ast.html#module-ast).2223Для каждого символа левой части абстрактной грамматики определён один класс (например, `ast.stmt` или `ast.expr`). Кроме того, для каждого конструктора правой части определён один класс; эти классы наследуют от классов левой части. Например, `ast.BinOp` наследует от `ast.expr`. Для правил вывода с альтернативами (так называемых «сумм») класс левой части является абстрактным: создаются только экземпляры конкретных конструкторных узлов.2425#### `_fields`2627Каждый конкретный класс имеет атрибут [`_fields`](https://python-all.ru/3.2/library/ast.html#ast.AST._fields), который содержит имена всех дочерних узлов.2829Каждый экземпляр конкретного класса имеет по одному атрибуту для каждого дочернего узла, тип которого определён грамматикой. Например, экземпляры `ast.BinOp` имеют атрибут `left` типа `ast.expr`.3031Если эти атрибуты помечены как необязательные в грамматике (с помощью вопросительного знака), их значением может быть `None`. Если атрибуты могут иметь ноль или более значений (помечены звёздочкой), значения представляются в виде списков Python. Все возможные атрибуты должны присутствовать и иметь допустимые значения при компиляции AST с помощью [`compile()`](https://python-all.ru/3.2/library/functions.html#compile).3233#### `lineno`3435#### `col_offset`3637Экземпляры подклассов `ast.expr` и `ast.stmt` имеют атрибуты [`lineno`](https://python-all.ru/3.2/library/ast.html#ast.AST.lineno) и [`col_offset`](https://python-all.ru/3.2/library/ast.html#ast.AST.col_offset). [`lineno`](https://python-all.ru/3.2/library/ast.html#ast.AST.lineno) – это номер строки исходного текста (нумерация с 1, так что первая строка – строка 1), а [`col_offset`](https://python-all.ru/3.2/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## 30.2.2. Абстрактная грамматика6566Модуль определяет строковую константу `__version__`, которая содержит десятичный номер ревизии Subversion файла, показанного ниже.6768Абстрактная грамматика в настоящее время определяется следующим образом:6970```python71-- ASDL's four builtin types are identifier, int, string, object7273module Python version "$Revision$"74{75	mod = Module(stmt* body)76	    | Interactive(stmt* body)77	    | Expression(expr body)7879	    -- not really an actual node but useful in Jython's typesystem.80	    | Suite(stmt* body)8182	stmt = FunctionDef(identifier name, arguments args, 83                           stmt* body, expr* decorator_list, expr? returns)84	      | ClassDef(identifier name, 85			 expr* bases,86			 keyword* keywords,87			 expr? starargs,88			 expr? kwargs,89			 stmt* body,90			 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	      -- use 'orelse' because else is a keyword in target languages98	      | For(expr target, expr iter, stmt* body, stmt* orelse)99	      | While(expr test, stmt* body, stmt* orelse)100	      | If(expr test, stmt* body, stmt* orelse)101	      | With(expr context_expr, expr? optional_vars, stmt* body)102103	      | Raise(expr? exc, expr? cause)104	      | TryExcept(stmt* body, excepthandler* handlers, stmt* orelse)105	      | TryFinally(stmt* body, stmt* finalbody)106	      | Assert(expr test, expr? msg)107108	      | Import(alias* names)109	      | ImportFrom(identifier? module, alias* names, int? level)110111	      | Global(identifier* names)112	      | Nonlocal(identifier* names)113	      | Expr(expr value)114	      | Pass | Break | Continue115116	      -- XXX Jython will be different117	      -- col_offset is the byte offset in the utf8 string the parser uses118	      attributes (int lineno, int col_offset)119120	      -- BoolOp() can use left & right?121	expr = BoolOp(boolop op, expr* values)122	     | BinOp(expr left, operator op, expr right)123	     | UnaryOp(unaryop op, expr operand)124	     | Lambda(arguments args, expr body)125	     | IfExp(expr test, expr body, expr orelse)126	     | Dict(expr* keys, expr* values)127	     | Set(expr* elts)128	     | ListComp(expr elt, comprehension* generators)129	     | SetComp(expr elt, comprehension* generators)130	     | DictComp(expr key, expr value, comprehension* generators)131	     | GeneratorExp(expr elt, comprehension* generators)132	     -- the grammar constrains where yield expressions can occur133	     | Yield(expr? value)134	     -- need sequences for compare to distinguish between135	     -- x < 4 < 3 and (x < 4) < 3136	     | Compare(expr left, cmpop* ops, expr* comparators)137	     | Call(expr func, expr* args, keyword* keywords,138			 expr? starargs, expr? kwargs)139	     | Num(object n) -- a number as a PyObject.140	     | Str(string s) -- need to specify raw, unicode, etc?141	     | Bytes(string s)142	     | Ellipsis143	     -- other literals? bools?144145	     -- the following expression can appear in assignment context146	     | Attribute(expr value, identifier attr, expr_context ctx)147	     | Subscript(expr value, slice slice, expr_context ctx)148	     | Starred(expr value, expr_context ctx)149	     | Name(identifier id, expr_context ctx)150	     | List(expr* elts, expr_context ctx) 151	     | Tuple(expr* elts, expr_context ctx)152153	      -- col_offset is the byte offset in the utf8 string the parser uses154	      attributes (int lineno, int col_offset)155156	expr_context = Load | Store | Del | AugLoad | AugStore | Param157158	slice = Slice(expr? lower, expr? upper, expr? step) 159	      | ExtSlice(slice* dims) 160	      | Index(expr value) 161162	boolop = And | Or 163164	operator = Add | Sub | Mult | Div | Mod | Pow | LShift 165                 | RShift | BitOr | BitXor | BitAnd | FloorDiv166167	unaryop = Invert | Not | UAdd | USub168169	cmpop = Eq | NotEq | Lt | LtE | Gt | GtE | Is | IsNot | In | NotIn170171	comprehension = (expr target, expr iter, expr* ifs)172173	-- not sure what to call the first argument for raise and except174	excepthandler = ExceptHandler(expr? type, identifier? name, stmt* body)175	                attributes (int lineno, int col_offset)176177	arguments = (arg* args, identifier? vararg, expr? varargannotation,178                     arg* kwonlyargs, identifier? kwarg,179                     expr? kwargannotation, expr* defaults,180                     expr* kw_defaults)181	arg = (identifier arg, expr? annotation)182183        -- keyword arguments supplied to call184        keyword = (identifier arg, expr value)185186        -- import name with optional 'as' alias.187        alias = (identifier name, identifier? asname)188}189```190191## 30.2.3. [`ast`](https://python-all.ru/3.2/library/ast.html#module-ast) Вспомогательные функции192193Помимо классов узлов, модуль [`ast`](https://python-all.ru/3.2/library/ast.html#module-ast) определяет следующие вспомогательные функции и классы для обхода абстрактных синтаксических деревьев:194195#### `ast.parse(source, filename='<unknown>', mode='exec')`196197Разбирает исходный код в узел AST. Эквивалентно `compile(source, filename, mode, ast.PyCF_ONLY_AST)`.198199#### `ast.literal_eval(node_or_string)`200201Безопасно вычисляет узел выражения или строку, содержащую Python-выражение. Предоставленная строка или узел может содержать только следующие литеральные структуры Python: строки, байты, числа, кортежи, списки, словари, множества, булевы значения и `None`.202203Это можно использовать для безопасного вычисления строк, содержащих выражения Python из ненадёжных источников, без необходимости самостоятельно их разбирать.204205Изменено в версии 3.2: Теперь допускаются литералы bytes и set.206207#### `ast.get_docstring(node, clean=True)`208209Возвращает docstring заданного *node* (который должен быть узлом `FunctionDef`, `ClassDef` или `Module` ), или `None`, если docstring нет. Если *clean* равно True, очищает отступы docstring с помощью [`inspect.cleandoc()`](https://python-all.ru/3.2/library/inspect.html#inspect.cleandoc).210211#### `ast.fix_missing_locations(node)`212213При компиляции дерева узлов с помощью [`compile()`](https://python-all.ru/3.2/library/functions.html#compile) компилятор ожидает атрибуты `lineno` и `col_offset` для каждого узла, который их поддерживает. Заполнять их вручную для сгенерированных узлов довольно утомительно, поэтому эта вспомогательная функция рекурсивно добавляет эти атрибуты, если они ещё не установлены, присваивая им значения родительского узла. Она работает рекурсивно, начиная с *node*.214215#### `ast.increment_lineno(node, n=1)`216217Увеличить номер строки каждого узла в дереве, начиная с *node*, на *n*. Это полезно для «переноса кода» в другое место в файле.218219#### `ast.copy_location(new_node, old_node)`220221Копирует информацию о положении в исходном коде (`lineno` и `col_offset`) из *old\_node* в *new\_node*, если это возможно, и возвращает *new\_node*.222223#### `ast.iter_fields(node)`224225Генерирует кортеж `(fieldname, value)` для каждого поля из `node._fields`, которое присутствует в *node*.226227#### `ast.iter_child_nodes(node)`228229Генерирует все непосредственные дочерние узлы *node*, то есть все поля, являющиеся узлами, и все элементы полей, являющихся списками узлов.230231#### `ast.walk(node)`232233Рекурсивно генерирует все узлы-потомки в дереве, начиная с *node* (включая сам *node*), в произвольном порядке. Это полезно, если требуется только изменить узлы на месте, а контекст не важен.234235#### `class ast.NodeVisitor`236237Базовый класс для обхода абстрактного синтаксического дерева, который вызывает функцию посетителя для каждого найденного узла. Эта функция может возвращать значение, которое передаётся методом [`visit()`](https://python-all.ru/3.2/library/ast.html#ast.NodeVisitor.visit).238239Этот класс предназначен для наследования; в подклассе добавляются методы-посетители.240241#### `visit(node)`242243Посещает узел. Реализация по умолчанию вызывает метод `self.visit_classname`, где *classname* – это имя класса узла, или [`generic_visit()`](https://python-all.ru/3.2/library/ast.html#ast.NodeVisitor.generic_visit), если такой метод не существует.244245#### `generic_visit(node)`246247Этот обходчик вызывает [`visit()`](https://python-all.ru/3.2/library/ast.html#ast.NodeVisitor.visit) для всех дочерних узлов данного узла.248249Обратите внимание, что дочерние узлы узлов, для которых определён пользовательский метод обхода, не будут посещены, если обходчик не вызовет [`generic_visit()`](https://python-all.ru/3.2/library/ast.html#ast.NodeVisitor.generic_visit) или не посетит их самостоятельно.250251Не используйте [`NodeVisitor`](https://python-all.ru/3.2/library/ast.html#ast.NodeVisitor) для внесения изменений в узлы во время обхода. Для этого существует специальный обходчик ([`NodeTransformer`](https://python-all.ru/3.2/library/ast.html#ast.NodeTransformer)), позволяющий вносить изменения.252253#### `class ast.NodeTransformer`254255Подкласс [`NodeVisitor`](https://python-all.ru/3.2/library/ast.html#ast.NodeVisitor), который обходит абстрактное синтаксическое дерево и позволяет изменять узлы.256257[`NodeTransformer`](https://python-all.ru/3.2/library/ast.html#ast.NodeTransformer) обходит AST и использует возвращаемое значение методов обхода для замены или удаления старого узла. Если возвращаемое значение метода обхода равно `None`, узел удаляется из своего местоположения; в противном случае он заменяется возвращаемым значением. Возвращаемое значение может быть исходным узлом, и в этом случае замена не производится.258259Вот пример преобразователя, который заменяет все обращения к имени (`foo`) на `data['foo']`:260261```python262class RewriteName(NodeTransformer):263264    def visit_Name(self, node):265        return copy_location(Subscript(266            value=Name(id='data', ctx=Load()),267            slice=Index(value=Str(s=node.id)),268            ctx=node.ctx269        ), node)270```271272Имейте в виду, что если у узла, с которым вы работаете, есть дочерние узлы, вы должны либо преобразовать дочерние узлы самостоятельно, либо сначала вызвать метод `generic_visit()` для этого узла.273274Для узлов, входящих в состав набора инструкций (это относится ко всем узлам инструкций), посетитель может также возвращать список узлов, а не один узел.275276Обычно преобразователь используется следующим образом:277278```python279node = YourTransformer().visit(node)280```281282#### `ast.dump(node, annotate_fields=True, include_attributes=False)`283284Возвращает форматированное представление дерева в виде дампа из объекта *node*. Это в основном полезно для целей отладки. Возвращаемая строка покажет имена и значения полей. Это делает код невозможным для выполнения, поэтому если требуется выполнимость, *annotate\_fields* должен быть установлен в False. Атрибуты, такие как номера строк и смещения столбцов, по умолчанию не выводятся. Если это нужно, *include\_attributes* можно установить в `True`.285