ast — Деревья абстрактного синтаксиса
Новая версия 2.5: Модуль низкого уровня _ast содержащий только классы узлов.
Новая версия 2.6: Модуль высокого уровня ast содержащий все вспомогательные функции.
Исходный код: Lib/ast.py
Модуль ast помогает приложениям Python обрабатывать деревья абстрактного синтаксиса Python. Сам абстрактный синтаксис может меняться с каждой версией Python; этот модуль помогает программно определить, как выглядит текущая грамматика.
Дерево абстрактного синтаксиса может быть сгенерировано, передав ast.PyCF_ONLY_AST в качестве флага функции compile() или используя вспомогательную функцию parse() в этом модуле. Результатом будет дерево объектов, классы которых наследуются от ast.AST. Дерево абстрактного синтаксиса может быть скомпилировано в объект кода Python с помощью встроенной функции compile().
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)Новая версия 2.6: Конструктор, как описано выше, был добавлен. В Python 2.5 узлы нужно было создавать, вызывая конструктор класса без аргументов и устанавливая атрибуты впоследствии.
-
2. Абстрактная грамматика
Модуль определяет строковую константу __version__, которая представляет собой номер десятичной версии Subversion файла, приведенного ниже.
В настоящее время абстрактная грамматика определяется следующим образом:
-- ASDL's five builtin types are identifier, int, string, object, bool
module Python version "$Revision$"
{
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)
| ClassDef(identifier name, expr* bases, stmt* body, expr* decorator_list)
| Return(expr? value)
| Delete(expr* targets)
| Assign(expr* targets, expr value)
| AugAssign(expr target, operator op, expr value)
-- not sure if bool is allowed, can always use int
| Print(expr? dest, expr* values, bool nl)
-- use 'orelse' because else is a keyword in target languages
| For(expr target, expr iter, stmt* body, stmt* orelse)
| While(expr test, stmt* body, stmt* orelse)
| If(expr test, stmt* body, stmt* orelse)
| With(expr context_expr, expr? optional_vars, stmt* body)
-- 'type' is a bad name
| Raise(expr? type, expr? inst, expr? tback)
| TryExcept(stmt* body, excepthandler* handlers, stmt* orelse)
| TryFinally(stmt* body, stmt* finalbody)
| Assert(expr test, expr? msg)
| Import(alias* names)
| ImportFrom(identifier? module, alias* names, int? level)
-- Doesn't capture requirement that locals must be
-- defined if globals is
-- still supports use as a function!
| Exec(expr body, expr? globals, expr? locals)
| Global(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
| Yield(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,
expr? starargs, expr? kwargs)
| Repr(expr value)
| Num(object n) -- a number as a PyObject.
| Str(string s) -- need to specify raw, unicode, etc?
-- other literals? bools?
-- the following expression can appear in assignment context
| Attribute(expr value, identifier attr, expr_context ctx)
| Subscript(expr value, slice slice, 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 = Ellipsis | Slice(expr? lower, expr? upper, expr? step)
| ExtSlice(slice* dims)
| Index(expr value)
boolop = And | Or
operator = Add | Sub | Mult | 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)
-- not sure what to call the first argument for raise and except
excepthandler = ExceptHandler(expr? type, expr? name, stmt* body)
attributes (int lineno, int col_offset)
arguments = (expr* args, identifier? vararg,
identifier? kwarg, expr* defaults)
-- keyword arguments supplied to call
keyword = (identifier arg, expr value)
-- import name with optional 'as' alias.
alias = (identifier name, identifier? asname)
}
3. Вспомогательные функции ast
Новая версия 2.6.
Помимо классов узлов, модуль 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) -
Безопасно оценить узел выражения или строку Unicode или Latin-1, содержащую Python-литерал или представление контейнера. Предоставленная строка или узел могут содержать только следующие структуры Python-литералов: строки, числа, кортежи, списки, словари, булевы значения и
None.Это можно использовать для безопасной оценки строк, содержащих значения Python из ненадежных источников, без необходимости самим парсить эти значения. Она не способна оценивать произвольно сложные выражения, например, с операторами или индексированием.
Предупреждение
Возможно аварийное завершение интерпретатора Python с достаточно длинной/сложной строкой из-за ограничений глубины стека в компиляторе AST Python.
-
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.
© 2001–2020 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/2.7/library/ast.html