ast — Деревья абстрактного синтаксиса
Исходный код: Lib/ast.py
Модуль ast помогает приложениям Python обрабатывать деревья абстрактного синтаксиса Python. Сам абстрактный синтаксис может меняться с каждой версией Python; этот модуль помогает программно узнать, какой синтаксис используется в текущей версии.
Дерево абстрактного синтаксиса можно сгенерировать, передав ast.PyCF_ONLY_AST в качестве флага функции compile() или используя функцию parse() из этого модуля. Результатом будет дерево объектов, классы которых все наследуются от ast.AST. Дерево абстрактного синтаксиса можно скомпилировать в объект кода Python с помощью встроенной функции compile().
32.2.1. Классы узлов
-
class ast.AST -
Это базовый класс для всех классов узлов AST. Фактические классы узлов производятся из файла
Parser/Python.asdl, который воспроизведён ниже. Они определены в модуле_astC и повторно экспортированы вast.Для каждого левого символа в абстрактной грамматике определён один класс (например,
ast.stmtилиast.expr). Кроме того, для каждого конструктора в правой части определён один класс; эти классы наследуют классы левых частей дерева. Например,ast.BinOpнаследует отast.expr. Для правил вывода с альтернативами (также известными как «суммы») класс левой части является абстрактным: создаются только экземпляры конкретных узлов конструкторов.-
_fields -
Каждый конкретный класс имеет атрибут
_fields, который содержит имена всех дочерних узлов.Каждый экземпляр конкретного класса имеет один атрибут для каждого дочернего узла, типа, определённого в грамматике. Например, экземпляры
ast.BinOpимеют атрибутleftтипаast.expr.Если эти атрибуты помечены как необязательные в грамматике (с помощью вопросительного знака), значение может быть
None. Если атрибуты могут иметь ноль или более значений (помечены звёздочкой), значения представлены в виде списков Python. Все возможные атрибуты должны быть присутствовать и иметь допустимые значения при компиляции AST с помощьюcompile().
-
lineno -
col_offset -
Экземпляры классов
ast.exprиast.stmtимеют атрибутыlinenoиcol_offset. Атрибутlineno— номер строки исходного текста (индексируется с 1, поэтому первая строка — строка 1), а атрибутcol_offset— смещение байтов первого токена UTF-8, который сгенерировал узел. Смещение в UTF-8 записывается, так как парсер использует UTF-8 внутри.
Конструктор класса
ast.Tанализирует свои аргументы следующим образом:- Если есть позиционные аргументы, их должно быть столько же, сколько элементов в
T._fields; они будут назначены в качестве атрибутов этих имён. - Если есть именованные аргументы, они будут устанавливать атрибуты с теми же именами в заданные значения.
Например, для создания и заполнения узла
ast.UnaryOpможно использоватьnode = ast.UnaryOp() node.op = ast.USub() node.operand = ast.Num() node.operand.n = 5 node.operand.lineno = 0 node.operand.col_offset = 0 node.lineno = 0 node.col_offset = 0
или более компактный способ
node = ast.UnaryOp(ast.USub(), ast.Num(5, lineno=0, col_offset=0), lineno=0, col_offset=0) -
32.2.2. Абстрактная грамматика
Абстрактная грамматика определяется следующим образом:
-- ASDL's 7 builtin types are:
-- identifier, int, string, bytes, object, singleton, constant
--
-- singleton: None, True or False
-- constant can be None, whereas None means "no value" for object.
module Python
{
mod = Module(stmt* body)
| Interactive(stmt* body)
| Expression(expr body)
-- not really an actual node but useful in Jython's typesystem.
| Suite(stmt* body)
stmt = FunctionDef(identifier name, arguments args,
stmt* body, expr* decorator_list, expr? returns)
| AsyncFunctionDef(identifier name, arguments args,
stmt* body, expr* decorator_list, expr? returns)
| ClassDef(identifier name,
expr* bases,
keyword* keywords,
stmt* body,
expr* decorator_list)
| Return(expr? value)
| Delete(expr* targets)
| Assign(expr* targets, expr value)
| AugAssign(expr target, operator op, expr value)
-- 'simple' indicates that we annotate simple name without parens
| AnnAssign(expr target, expr annotation, expr? value, int simple)
-- use 'orelse' because else is a keyword in target languages
| For(expr target, expr iter, stmt* body, stmt* orelse)
| AsyncFor(expr target, expr iter, stmt* body, stmt* orelse)
| While(expr test, stmt* body, stmt* orelse)
| If(expr test, stmt* body, stmt* orelse)
| With(withitem* items, stmt* body)
| AsyncWith(withitem* items, stmt* body)
| Raise(expr? exc, expr? cause)
| Try(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody)
| Assert(expr test, expr? msg)
| Import(alias* names)
| ImportFrom(identifier? module, alias* names, int? level)
| Global(identifier* names)
| Nonlocal(identifier* names)
| Expr(expr value)
| Pass | Break | Continue
-- XXX Jython will be different
-- col_offset is the byte offset in the utf8 string the parser uses
attributes (int lineno, int col_offset)
-- BoolOp() can use left & right?
expr = BoolOp(boolop op, expr* values)
| BinOp(expr left, operator op, expr right)
| UnaryOp(unaryop op, expr operand)
| Lambda(arguments args, expr body)
| IfExp(expr test, expr body, expr orelse)
| Dict(expr* keys, expr* values)
| Set(expr* elts)
| ListComp(expr elt, comprehension* generators)
| SetComp(expr elt, comprehension* generators)
| DictComp(expr key, expr value, comprehension* generators)
| GeneratorExp(expr elt, comprehension* generators)
-- the grammar constrains where yield expressions can occur
| Await(expr value)
| Yield(expr? value)
| YieldFrom(expr value)
-- need sequences for compare to distinguish between
-- x < 4 < 3 and (x < 4) < 3
| Compare(expr left, cmpop* ops, expr* comparators)
| Call(expr func, expr* args, keyword* keywords)
| Num(object n) -- a number as a PyObject.
| Str(string s) -- need to specify raw, unicode, etc?
| FormattedValue(expr value, int? conversion, expr? format_spec)
| JoinedStr(expr* values)
| Bytes(bytes s)
| NameConstant(singleton value)
| Ellipsis
| Constant(constant value)
-- the following expression can appear in assignment context
| Attribute(expr value, identifier attr, expr_context ctx)
| Subscript(expr value, slice slice, expr_context ctx)
| Starred(expr value, expr_context ctx)
| Name(identifier id, expr_context ctx)
| List(expr* elts, expr_context ctx)
| Tuple(expr* elts, expr_context ctx)
-- col_offset is the byte offset in the utf8 string the parser uses
attributes (int lineno, int col_offset)
expr_context = Load | Store | Del | AugLoad | AugStore | Param
slice = Slice(expr? lower, expr? upper, expr? step)
| ExtSlice(slice* dims)
| Index(expr value)
boolop = And | Or
operator = Add | Sub | Mult | MatMult | Div | Mod | Pow | LShift
| RShift | BitOr | BitXor | BitAnd | FloorDiv
unaryop = Invert | Not | UAdd | USub
cmpop = Eq | NotEq | Lt | LtE | Gt | GtE | Is | IsNot | In | NotIn
comprehension = (expr target, expr iter, expr* ifs, int is_async)
excepthandler = ExceptHandler(expr? type, identifier? name, stmt* body)
attributes (int lineno, int col_offset)
arguments = (arg* args, arg? vararg, arg* kwonlyargs, expr* kw_defaults,
arg? kwarg, expr* defaults)
arg = (identifier arg, expr? annotation)
attributes (int lineno, int col_offset)
-- keyword arguments supplied to call (NULL identifier for **kwargs)
keyword = (identifier? arg, expr value)
-- import name with optional 'as' alias.
alias = (identifier name, identifier? asname)
withitem = (expr context_expr, expr? optional_vars)
}
32.2.3. Инструменты для работы с AST
Помимо классов узлов, модуль ast определяет следующие вспомогательные функции и классы для обхода деревьев абстрактного синтаксиса:
-
ast.parse(source, filename='<unknown>', mode='exec') -
Разбор исходного кода в узел AST. Эквивалентно
compile(source, filename, mode, ast.PyCF_ONLY_AST).Предупреждение
Возможно аварийное завершение интерпретатора Python с достаточно большой/сложной строкой из-за ограничений глубины стека в компиляторе AST Python.
-
ast.literal_eval(node_or_string) -
Безопасная оценка выражения узла или строки, содержащей Python-литерал или дисплей контейнера. Предоставленная строка или узел может содержать только следующие структуры Python-литералов: строки, байты, числа, кортежи, списки, словари, множества, булевы значения и
None.Это можно использовать для безопасной оценки строк, содержащих значения Python из ненадежных источников, без необходимости самостоятельно парсить значения. Она не способна оценивать произвольно сложные выражения, например, с операторами или индексацией.
Предупреждение
Возможно аварийное завершение интерпретатора Python с достаточно большой/сложной строкой из-за ограничений глубины стека в компиляторе AST Python.
Изменено в версии 3.2: Теперь поддерживает литералы байтов и множеств.
-
ast.get_docstring(node, clean=True) -
Возвращает строку документации заданного узла node (который должен быть узлом
FunctionDef,ClassDefилиModule), илиNoneесли у него нет строки документации. Если clean равно True, очищает отступы в строке документации с помощьюinspect.cleandoc().
-
ast.fix_missing_locations(node) -
При компиляции дерева узлов с помощью
compile()компилятор ожидает атрибутыlinenoиcol_offsetдля каждого узла, который их поддерживает. Это довольно утомительно для заполнения сгенерированных узлов, поэтому этот помощник добавляет эти атрибуты рекурсивно, где они не заданы, устанавливая их в значения родительского узла. Он работает рекурсивно, начиная с узла node.
-
ast.increment_lineno(node, n=1) -
Увеличивает номер строки каждого узла в дереве, начиная с node, на n. Это полезно для «перемещения кода» в другое место в файле.
-
ast.copy_location(new_node, old_node) -
Копирует местоположение источника (
linenoиcol_offset) из old_node в new_node, если возможно, и возвращает new_node.
-
ast.iter_fields(node) -
Возвращает кортеж
(fieldname, value)для каждого поля вnode._fieldsприсутствующего в node.
-
ast.iter_child_nodes(node) -
Возвращает все непосредственные дочерние узлы node, то есть все поля, которые являются узлами, и все элементы полей, которые являются списками узлов.
-
ast.walk(node) -
Рекурсивно возвращает всех потомков узла в дереве, начиная с node (включая node), в произвольном порядке. Это полезно, если вы хотите только изменить узлы на месте и не беспокоитесь о контексте.
-
class ast.NodeVisitor -
Базовый класс посетителя узлов, который обходит дерево абстрактного синтаксиса и вызывает функцию посетителя для каждого найденного узла. Эта функция может вернуть значение, которое пересылается методом
visit().Этот класс предназначен для наследования, при этом подкласс добавляет методы посетителей.
-
visit(node) -
Посещение узла. По умолчанию вызывается метод с именем
self.visit_classname, где classname — имя класса узла, илиgeneric_visit()если такой метод не существует.
-
generic_visit(node) -
Этот посетитель вызывает
visit()для всех дочерних узлов узла.Обратите внимание, что дочерние узлы узлов, имеющих пользовательский метод посетителя, не будут посещены, если посетитель не вызовет
generic_visit()или сам их не посетит.
Не используйте
NodeVisitorесли вы хотите вносить изменения в узлы во время обхода. Для этого существует специальный посетитель (NodeTransformer), который позволяет вносить изменения. -
-
class ast.NodeTransformer -
Подкласс
NodeVisitor, который обходит абстрактное синтаксическое дерево и позволяет изменять узлы.NodeTransformerбудет обходить АСТ и использовать возвращаемое значение методов посетителя для замены или удаления старого узла. Если возвращаемое значение метода посетителя равноNone, узел будет удалён из его местоположения, в противном случае он будет заменён возвращаемым значением. Возвращаемое значение может быть исходным узлом, в этом случае замена не произойдёт.Вот пример трансформатора, который переписывает все случаи поиска по имени (
foo) наdata['foo']:class RewriteName(NodeTransformer): def visit_Name(self, node): return copy_location(Subscript( value=Name(id='data', ctx=Load()), slice=Index(value=Str(s=node.id)), ctx=node.ctx ), node)Помните, что если у обрабатываемого узла есть дочерние узлы, вы должны либо преобразовать дочерние узлы самостоятельно, либо сначала вызвать метод
generic_visit()для узла.Для узлов, которые были частью коллекции операторов (это относится ко всем узлам операторов), посетитель также может вернуть список узлов вместо одного узла.
Обычно вы используете трансформатор так:
node = YourTransformer().visit(node)
-
ast.dump(node, annotate_fields=True, include_attributes=False) -
Возвращает отформатированный вывод дерева в node. Это в основном полезно для отладки. Возвращаемая строка отобразит имена и значения полей. Это делает код невозможным для оценки, поэтому, если нужна оценка, annotate_fields должно быть установлено в
False. Атрибуты, такие как номера строк и смещения столбцов, по умолчанию не выводятся. Если это нужно, include_attributes можно установить вTrue.
См. также
Green Tree Snakes — внешний ресурс документации, содержащий подробную информацию о работе с Python AST.
© 2001–2020 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.6/library/ast.html