ast — Абстрактные синтаксические деревья

Исходный код: Lib/ast.py.


Модуль ast помогает приложениям Python обрабатывать деревья грамматики абстрактного синтаксиса Python. Сам абстрактный синтаксис может меняться с каждым выпуском Python; этот модуль помогает программно узнать, как выглядит текущая грамматика.

Абстрактное синтаксическое дерево может быть сгенерировано путем передачи ast.PyCF_ONLY_AST в качестве флага встроенной функции compile() или с помощью помощника parse(), предоставленного в этом модуле. Результатом будет дерево объектов, все классы которых наследуются от ast.AST. Абстрактное синтаксическое дерево может быть скомпилировано в объект кода Python с помощью встроенной функции compile().

Абстрактная грамматика

В настоящее время абстрактная грамматика определяется следующим образом:

-- ASDL's 4 builtin types are:
-- identifier, int, string, constant

module Python
{
    mod = Module(stmt* body, type_ignore* type_ignores)
        | Interactive(stmt* body)
        | Expression(expr body)
        | FunctionType(expr* argtypes, expr returns)

    stmt = FunctionDef(identifier name, arguments args,
                       stmt* body, expr* decorator_list, expr? returns,
                       string? type_comment)
          | AsyncFunctionDef(identifier name, arguments args,
                             stmt* body, expr* decorator_list, expr? returns,
                             string? type_comment)

          | ClassDef(identifier name,
             expr* bases,
             keyword* keywords,
             stmt* body,
             expr* decorator_list)
          | Return(expr? value)

          | Delete(expr* targets)
          | Assign(expr* targets, expr value, string? type_comment)
          | 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, string? type_comment)
          | AsyncFor(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment)
          | While(expr test, stmt* body, stmt* orelse)
          | If(expr test, stmt* body, stmt* orelse)
          | With(withitem* items, stmt* body, string? type_comment)
          | AsyncWith(withitem* items, stmt* body, string? type_comment)

          | Match(expr subject, match_case* cases)

          | 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

          -- col_offset is the byte offset in the utf8 string the parser uses
          attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)

          -- BoolOp() can use left & right?
    expr = BoolOp(boolop op, expr* values)
         | NamedExpr(expr target, expr value)
         | 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)
         | FormattedValue(expr value, int conversion, expr? format_spec)
         | JoinedStr(expr* values)
         | Constant(constant value, string? kind)

         -- the following expression can appear in assignment context
         | Attribute(expr value, identifier attr, expr_context ctx)
         | Subscript(expr value, expr 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)

         -- can appear only in Subscript
         | Slice(expr? lower, expr? upper, expr? step)

          -- col_offset is the byte offset in the utf8 string the parser uses
          attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)

    expr_context = Load | Store | Del

    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, int? end_lineno, int? end_col_offset)

    arguments = (arg* posonlyargs, arg* args, arg? vararg, arg* kwonlyargs,
                 expr* kw_defaults, arg? kwarg, expr* defaults)

    arg = (identifier arg, expr? annotation, string? type_comment)
           attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)

    -- keyword arguments supplied to call (NULL identifier for **kwargs)
    keyword = (identifier? arg, expr value)
               attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)

    -- import name with optional 'as' alias.
    alias = (identifier name, identifier? asname)
             attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)

    withitem = (expr context_expr, expr? optional_vars)

    match_case = (pattern pattern, expr? guard, stmt* body)

    pattern = MatchValue(expr value)
            | MatchSingleton(constant value)
            | MatchSequence(pattern* patterns)
            | MatchMapping(expr* keys, pattern* patterns, identifier? rest)
            | MatchClass(expr cls, pattern* patterns, identifier* kwd_attrs, pattern* kwd_patterns)

            | MatchStar(identifier? name)
            -- The optional "rest" MatchMapping parameter handles capturing extra mapping keys

            | MatchAs(pattern? pattern, identifier? name)
            | MatchOr(pattern* patterns)

             attributes (int lineno, int col_offset, int end_lineno, int end_col_offset)

    type_ignore = TypeIgnore(int lineno, string tag)
}

Классы узлов

class ast.AST

Это основа всех классов узлов AST. Фактические классы узлов являются производными от файла Parser/Python.asdl, который воспроизводится above. Они определены в модуле _ast на языке C и реэкспортированы в ast.

Для каждого символа левой стороны в абстрактной грамматике определен один класс (например, ast.stmt или ast.expr). Кроме того, для каждого конструктора правой стороны определен один класс; эти классы наследуются от классов для деревьев левой стороны. Например, ast.BinOp наследуется от ast.expr. Для производственных правил с альтернативами (они же «суммы») класс левой стороны является абстрактным: создаются только экземпляры конкретных узлов конструктора.

_fields

Каждый конкретный класс имеет атрибут _fields, который дает имена всех дочерних узлов.

Каждый экземпляр конкретного класса имеет один атрибут для каждого дочернего узла, тип которого определен в грамматике. Например, экземпляры ast.BinOp имеют атрибут left типа ast.expr.

Если эти атрибуты помечены в грамматике как необязательные (с помощью знака вопроса), то значение может быть None. Если атрибуты могут иметь ноль или более значений (помечены звездочкой), то значения представляются в виде списков Python. Все возможные атрибуты должны присутствовать и иметь допустимые значения при компиляции AST с помощью compile().

lineno
col_offset
end_lineno
end_col_offset

Экземпляры подклассов ast.expr и ast.stmt имеют атрибуты lineno, col_offset, end_lineno и end_col_offset. lineno и end_lineno - это номер первой и последней строки исходного текста (1-индексированный, так что первая строка - это строка 1), а col_offset и end_col_offset - это соответствующие смещения байтов UTF-8 первой и последней лексемы, породившей узел. Смещение UTF-8 записывается потому, что синтаксический анализатор использует UTF-8 внутри системы.

Обратите внимание, что конечные позиции не требуются компилятору и поэтому являются необязательными. Конечное смещение находится после последнего символа, например, можно получить исходный сегмент однострочного узла выражения, используя source_line[node.col_offset : node.end_col_offset].

Конструктор класса ast.T разбирает свои аргументы следующим образом:

  • Если есть позиционные аргументы, их должно быть столько, сколько элементов в T._fields; они будут назначены как атрибуты этих имен.

  • Если есть аргументы в виде ключевых слов, они установят одноименные атрибуты в заданные значения.

Например, чтобы создать и заполнить узел ast.UnaryOp, вы можете использовать

node = ast.UnaryOp()
node.op = ast.USub()
node.operand = ast.Constant()
node.operand.value = 5
node.operand.lineno = 0
node.operand.col_offset = 0
node.lineno = 0
node.col_offset = 0

или более компактный

node = ast.UnaryOp(ast.USub(), ast.Constant(5, lineno=0, col_offset=0),
                   lineno=0, col_offset=0)

Изменено в версии 3.8: Класс ast.Constant теперь используется для всех констант.

Изменено в версии 3.9: Простые индексы представлены своим значением, расширенные срезы представлены в виде кортежей.

Не рекомендуется, начиная с версии 3.8: Старые классы ast.Num, ast.Str, ast.Bytes, ast.NameConstant и ast.Ellipsis все еще доступны, но они будут удалены в будущих выпусках Python. Тем временем их инстанцирование будет возвращать экземпляр другого класса.

Не рекомендуется, начиная с версии 3.9: Старые классы ast.Index и ast.ExtSlice все еще доступны, но они будут удалены в будущих выпусках Python. Тем временем их инстанцирование будет возвращать экземпляр другого класса.

Примечание

Представленные здесь описания конкретных классов узлов были первоначально адаптированы из фантастического проекта Green Tree Snakes и всех его участников.

Литература

class ast.Constant(value)

Постоянное значение. Атрибут value литерала Constant содержит объект Python, который он представляет. Представляемые значения могут быть простыми типами, такими как число, строка или None, а также неизменяемыми контейнерными типами (кортежи и фростенсеты), если все их элементы являются константными.

>>> print(ast.dump(ast.parse('123', mode='eval'), indent=4))
Expression(
    body=Constant(value=123))
class ast.FormattedValue(value, conversion, format_spec)

Узел, представляющий одно поле форматирования в f-строке. Если строка содержит одно поле форматирования и больше ничего, узел может быть изолирован, в противном случае он появляется в JoinedStr.

  • value - это любой узел выражения (например, литерал, переменная или вызов функции).

  • conversion - целое число:

    • -1: без форматирования

    • 115: !s форматирование строк

    • 114: !r повторное форматирование

    • 97: !a форматирование ascii

  • format_spec - это узел JoinedStr, представляющий форматирование значения, или None, если формат не был указан. Одновременно могут быть заданы и conversion, и format_spec.

class ast.JoinedStr(values)

f-строка, состоящая из серии узлов FormattedValue и Constant.

>>> print(ast.dump(ast.parse('f"sin({a}) is {sin(a):.3}"', mode='eval'), indent=4))
Expression(
    body=JoinedStr(
        values=[
            Constant(value='sin('),
            FormattedValue(
                value=Name(id='a', ctx=Load()),
                conversion=-1),
            Constant(value=') is '),
            FormattedValue(
                value=Call(
                    func=Name(id='sin', ctx=Load()),
                    args=[
                        Name(id='a', ctx=Load())],
                    keywords=[]),
                conversion=-1,
                format_spec=JoinedStr(
                    values=[
                        Constant(value='.3')]))]))
class ast.List(elts, ctx)
class ast.Tuple(elts, ctx)

Список или кортеж. elts содержит список узлов, представляющих элементы. ctx является Store, если контейнер является целью присваивания (т.е. (x,y)=something), и Load в противном случае.

>>> print(ast.dump(ast.parse('[1, 2, 3]', mode='eval'), indent=4))
Expression(
    body=List(
        elts=[
            Constant(value=1),
            Constant(value=2),
            Constant(value=3)],
        ctx=Load()))
>>> print(ast.dump(ast.parse('(1, 2, 3)', mode='eval'), indent=4))
Expression(
    body=Tuple(
        elts=[
            Constant(value=1),
            Constant(value=2),
            Constant(value=3)],
        ctx=Load()))
class ast.Set(elts)

Множество. elts содержит список узлов, представляющих элементы множества.

>>> print(ast.dump(ast.parse('{1, 2, 3}', mode='eval'), indent=4))
Expression(
    body=Set(
        elts=[
            Constant(value=1),
            Constant(value=2),
            Constant(value=3)]))
class ast.Dict(keys, values)

Словарь. keys и values содержат списки узлов, представляющих ключи и значения соответственно, в порядке соответствия (то, что будет возвращено при вызове dictionary.keys() и dictionary.values()).

При распаковке словаря с использованием словарных литералов расширяемое выражение идет в списке values, с None на соответствующей позиции в keys.

>>> print(ast.dump(ast.parse('{"a":1, **d}', mode='eval'), indent=4))
Expression(
    body=Dict(
        keys=[
            Constant(value='a'),
            None],
        values=[
            Constant(value=1),
            Name(id='d', ctx=Load())]))

Переменные

class ast.Name(id, ctx)

Имя переменной. id содержит имя в виде строки, а ctx является одним из следующих типов.

class ast.Load
class ast.Store
class ast.Del

Ссылки на переменные могут использоваться для загрузки значения переменной, присвоения ей нового значения или ее удаления. Ссылки на переменные имеют контекст, чтобы различать эти случаи.

>>> print(ast.dump(ast.parse('a'), indent=4))
Module(
    body=[
        Expr(
            value=Name(id='a', ctx=Load()))],
    type_ignores=[])

>>> print(ast.dump(ast.parse('a = 1'), indent=4))
Module(
    body=[
        Assign(
            targets=[
                Name(id='a', ctx=Store())],
            value=Constant(value=1))],
    type_ignores=[])

>>> print(ast.dump(ast.parse('del a'), indent=4))
Module(
    body=[
        Delete(
            targets=[
                Name(id='a', ctx=Del())])],
    type_ignores=[])
class ast.Starred(value, ctx)

Ссылка на переменную *var. value хранит переменную, обычно узел Name. Этот тип должен использоваться при построении узла Call с помощью *args.

>>> print(ast.dump(ast.parse('a, *b = it'), indent=4))
Module(
    body=[
        Assign(
            targets=[
                Tuple(
                    elts=[
                        Name(id='a', ctx=Store()),
                        Starred(
                            value=Name(id='b', ctx=Store()),
                            ctx=Store())],
                    ctx=Store())],
            value=Name(id='it', ctx=Load()))],
    type_ignores=[])

Выражения

class ast.Expr(value)

Когда выражение, например, вызов функции, появляется как самостоятельное утверждение с возвращаемым значением, которое не используется и не хранится, оно заворачивается в этот контейнер. value вмещает один из других узлов в этой секции, узел Constant, Name, Lambda, Yield или YieldFrom.

>>> print(ast.dump(ast.parse('-a'), indent=4))
Module(
    body=[
        Expr(
            value=UnaryOp(
                op=USub(),
                operand=Name(id='a', ctx=Load())))],
    type_ignores=[])
class ast.UnaryOp(op, operand)

Унарная операция. op - оператор, а operand - любой узел выражения.

class ast.UAdd
class ast.USub
class ast.Not
class ast.Invert

Токены унарных операторов. Not - ключевое слово not, Invert - оператор ~.

>>> print(ast.dump(ast.parse('not x', mode='eval'), indent=4))
Expression(
    body=UnaryOp(
        op=Not(),
        operand=Name(id='x', ctx=Load())))
class ast.BinOp(left, op, right)

Бинарная операция (например, сложение или деление). op - оператор, а left и right - любые узлы выражения.

>>> print(ast.dump(ast.parse('x + y', mode='eval'), indent=4))
Expression(
    body=BinOp(
        left=Name(id='x', ctx=Load()),
        op=Add(),
        right=Name(id='y', ctx=Load())))
class ast.Add
class ast.Sub
class ast.Mult
class ast.Div
class ast.FloorDiv
class ast.Mod
class ast.Pow
class ast.LShift
class ast.RShift
class ast.BitOr
class ast.BitXor
class ast.BitAnd
class ast.MatMult

Токены двоичных операторов.

class ast.BoolOp(op, values)

Булева операция, „или“ или „и“. op - это Or или And. values - это соответствующие значения. Последовательные операции с одним и тем же оператором, такие как a or b or c, сворачиваются в один узел с несколькими значениями.

Это не включает not, который является UnaryOp.

>>> print(ast.dump(ast.parse('x or y', mode='eval'), indent=4))
Expression(
    body=BoolOp(
        op=Or(),
        values=[
            Name(id='x', ctx=Load()),
            Name(id='y', ctx=Load())]))
class ast.And
class ast.Or

Токены булевых операторов.

class ast.Compare(left, ops, comparators)

Сравнение двух или более значений. left - первое значение в сравнении, ops - список операторов, а comparators - список значений после первого элемента в сравнении.

>>> print(ast.dump(ast.parse('1 <= a < 10', mode='eval'), indent=4))
Expression(
    body=Compare(
        left=Constant(value=1),
        ops=[
            LtE(),
            Lt()],
        comparators=[
            Name(id='a', ctx=Load()),
            Constant(value=10)]))
class ast.Eq
class ast.NotEq
class ast.Lt
class ast.LtE
class ast.Gt
class ast.GtE
class ast.Is
class ast.IsNot
class ast.In
class ast.NotIn

Токены оператора сравнения.

class ast.Call(func, args, keywords, starargs, kwargs)

Вызов функции. func - это функция, которая часто будет объектом Name или Attribute. Аргументы:

  • args содержит список аргументов, переданных по позиции.

  • keywords содержит список объектов keyword, представляющих аргументы, переданные ключевым словом.

При создании узла Call обязательными являются args и keywords, но они могут быть пустыми списками. starargs и kwargs являются необязательными.

>>> print(ast.dump(ast.parse('func(a, b=c, *d, **e)', mode='eval'), indent=4))
Expression(
    body=Call(
        func=Name(id='func', ctx=Load()),
        args=[
            Name(id='a', ctx=Load()),
            Starred(
                value=Name(id='d', ctx=Load()),
                ctx=Load())],
        keywords=[
            keyword(
                arg='b',
                value=Name(id='c', ctx=Load())),
            keyword(
                value=Name(id='e', ctx=Load()))]))
class ast.keyword(arg, value)

Аргумент ключевого слова для вызова функции или определения класса. arg - необработанная строка имени параметра, value - узел для передачи.

class ast.IfExp(test, body, orelse)

Выражение, такое как a if b else c. Каждое поле содержит один узел, поэтому в следующем примере все три узла являются узлами Name.

>>> print(ast.dump(ast.parse('a if b else c', mode='eval'), indent=4))
Expression(
    body=IfExp(
        test=Name(id='b', ctx=Load()),
        body=Name(id='a', ctx=Load()),
        orelse=Name(id='c', ctx=Load())))
class ast.Attribute(value, attr, ctx)

Доступ к атрибуту, например, d.keys. value - это узел, обычно Name. attr - это голая строка, дающая имя атрибута, а ctx - это Load, Store или Del в зависимости от того, как действует атрибут.

>>> print(ast.dump(ast.parse('snake.colour', mode='eval'), indent=4))
Expression(
    body=Attribute(
        value=Name(id='snake', ctx=Load()),
        attr='colour',
        ctx=Load()))
class ast.NamedExpr(target, value)

Именованное выражение. Этот узел AST создается оператором присваивания выражений (также известным как оператор моржа). В отличие от узла Assign, в котором первый аргумент может быть несколькими узлами, в данном случае и target, и value должны быть одиночными узлами.

>>> print(ast.dump(ast.parse('(x := 4)', mode='eval'), indent=4))
Expression(
    body=NamedExpr(
        target=Name(id='x', ctx=Store()),
        value=Constant(value=4)))

Subscripting

class ast.Subscript(value, slice, ctx)

Подскрипт, например l[1]. value - это подзаписываемый объект (обычно последовательность или отображение). slice - это индекс, фрагмент или ключ. Он может быть Tuple и содержать Slice. ctx - это Load, Store или Del в зависимости от действия, выполняемого с подзаписью.

>>> print(ast.dump(ast.parse('l[1:2, 3]', mode='eval'), indent=4))
Expression(
    body=Subscript(
        value=Name(id='l', ctx=Load()),
        slice=Tuple(
            elts=[
                Slice(
                    lower=Constant(value=1),
                    upper=Constant(value=2)),
                Constant(value=3)],
            ctx=Load()),
        ctx=Load()))
class ast.Slice(lower, upper, step)

Обычная нарезка (по форме lower:upper или lower:upper:step). Может встречаться только внутри поля slice в Subscript, либо непосредственно, либо как элемент Tuple.

>>> print(ast.dump(ast.parse('l[1:2]', mode='eval'), indent=4))
Expression(
    body=Subscript(
        value=Name(id='l', ctx=Load()),
        slice=Slice(
            lower=Constant(value=1),
            upper=Constant(value=2)),
        ctx=Load()))

Постижения

class ast.ListComp(elt, generators)
class ast.SetComp(elt, generators)
class ast.GeneratorExp(elt, generators)
class ast.DictComp(key, value, generators)

Понимание списков и множеств, генераторные выражения и понимания словарей. elt (или key и value) - это один узел, представляющий часть, которая будет оцениваться для каждого элемента.

generators - это список узлов comprehension.

>>> print(ast.dump(ast.parse('[x for x in numbers]', mode='eval'), indent=4))
Expression(
    body=ListComp(
        elt=Name(id='x', ctx=Load()),
        generators=[
            comprehension(
                target=Name(id='x', ctx=Store()),
                iter=Name(id='numbers', ctx=Load()),
                ifs=[],
                is_async=0)]))
>>> print(ast.dump(ast.parse('{x: x**2 for x in numbers}', mode='eval'), indent=4))
Expression(
    body=DictComp(
        key=Name(id='x', ctx=Load()),
        value=BinOp(
            left=Name(id='x', ctx=Load()),
            op=Pow(),
            right=Constant(value=2)),
        generators=[
            comprehension(
                target=Name(id='x', ctx=Store()),
                iter=Name(id='numbers', ctx=Load()),
                ifs=[],
                is_async=0)]))
>>> print(ast.dump(ast.parse('{x for x in numbers}', mode='eval'), indent=4))
Expression(
    body=SetComp(
        elt=Name(id='x', ctx=Load()),
        generators=[
            comprehension(
                target=Name(id='x', ctx=Store()),
                iter=Name(id='numbers', ctx=Load()),
                ifs=[],
                is_async=0)]))
class ast.comprehension(target, iter, ifs, is_async)

Одно предложение for в понимании. target - это ссылка, которую следует использовать для каждого элемента - обычно это узел Name или Tuple. iter - это объект для итерации. ifs - это список тестовых выражений: каждый пункт for может иметь несколько ifs.

is_async указывает на асинхронность понимания (использование async for вместо for). Значение - целое число (0 или 1).

>>> print(ast.dump(ast.parse('[ord(c) for line in file for c in line]', mode='eval'),
...                indent=4)) # Multiple comprehensions in one.
Expression(
    body=ListComp(
        elt=Call(
            func=Name(id='ord', ctx=Load()),
            args=[
                Name(id='c', ctx=Load())],
            keywords=[]),
        generators=[
            comprehension(
                target=Name(id='line', ctx=Store()),
                iter=Name(id='file', ctx=Load()),
                ifs=[],
                is_async=0),
            comprehension(
                target=Name(id='c', ctx=Store()),
                iter=Name(id='line', ctx=Load()),
                ifs=[],
                is_async=0)]))

>>> print(ast.dump(ast.parse('(n**2 for n in it if n>5 if n<10)', mode='eval'),
...                indent=4)) # generator comprehension
Expression(
    body=GeneratorExp(
        elt=BinOp(
            left=Name(id='n', ctx=Load()),
            op=Pow(),
            right=Constant(value=2)),
        generators=[
            comprehension(
                target=Name(id='n', ctx=Store()),
                iter=Name(id='it', ctx=Load()),
                ifs=[
                    Compare(
                        left=Name(id='n', ctx=Load()),
                        ops=[
                            Gt()],
                        comparators=[
                            Constant(value=5)]),
                    Compare(
                        left=Name(id='n', ctx=Load()),
                        ops=[
                            Lt()],
                        comparators=[
                            Constant(value=10)])],
                is_async=0)]))

>>> print(ast.dump(ast.parse('[i async for i in soc]', mode='eval'),
...                indent=4)) # Async comprehension
Expression(
    body=ListComp(
        elt=Name(id='i', ctx=Load()),
        generators=[
            comprehension(
                target=Name(id='i', ctx=Store()),
                iter=Name(id='soc', ctx=Load()),
                ifs=[],
                is_async=1)]))

Заявления

class ast.Assign(targets, value, type_comment)

Назначение. targets - это список узлов, а value - один узел.

Несколько узлов в targets представляют собой присвоение каждому из них одного и того же значения. Распаковка представлена помещением Tuple или List внутри targets.

type_comment

type_comment - необязательная строка с аннотацией типа в качестве комментария.

>>> print(ast.dump(ast.parse('a = b = 1'), indent=4)) # Multiple assignment
Module(
    body=[
        Assign(
            targets=[
                Name(id='a', ctx=Store()),
                Name(id='b', ctx=Store())],
            value=Constant(value=1))],
    type_ignores=[])

>>> print(ast.dump(ast.parse('a,b = c'), indent=4)) # Unpacking
Module(
    body=[
        Assign(
            targets=[
                Tuple(
                    elts=[
                        Name(id='a', ctx=Store()),
                        Name(id='b', ctx=Store())],
                    ctx=Store())],
            value=Name(id='c', ctx=Load()))],
    type_ignores=[])
class ast.AnnAssign(target, annotation, value, simple)

Назначение с аннотацией типа. target - это один узел, который может быть Name, Attribute или Subscript. annotation - это аннотация, например, узел Constant или Name. value - это один необязательный узел. simple - булево целое число, установленное в True для узла Name в target, которые не появляются между скобками и, следовательно, являются чистыми именами, а не выражениями.

>>> print(ast.dump(ast.parse('c: int'), indent=4))
Module(
    body=[
        AnnAssign(
            target=Name(id='c', ctx=Store()),
            annotation=Name(id='int', ctx=Load()),
            simple=1)],
    type_ignores=[])

>>> print(ast.dump(ast.parse('(a): int = 1'), indent=4)) # Annotation with parenthesis
Module(
    body=[
        AnnAssign(
            target=Name(id='a', ctx=Store()),
            annotation=Name(id='int', ctx=Load()),
            value=Constant(value=1),
            simple=0)],
    type_ignores=[])

>>> print(ast.dump(ast.parse('a.b: int'), indent=4)) # Attribute annotation
Module(
    body=[
        AnnAssign(
            target=Attribute(
                value=Name(id='a', ctx=Load()),
                attr='b',
                ctx=Store()),
            annotation=Name(id='int', ctx=Load()),
            simple=0)],
    type_ignores=[])

>>> print(ast.dump(ast.parse('a[1]: int'), indent=4)) # Subscript annotation
Module(
    body=[
        AnnAssign(
            target=Subscript(
                value=Name(id='a', ctx=Load()),
                slice=Constant(value=1),
                ctx=Store()),
            annotation=Name(id='int', ctx=Load()),
            simple=0)],
    type_ignores=[])
class ast.AugAssign(target, op, value)

Дополненное присваивание, например a += 1. В следующем примере target является узлом Name для x (с контекстом Store), op является Add, а value является Constant со значением 1.

Атрибут target не может быть класса Tuple или List, в отличие от целей Assign.

>>> print(ast.dump(ast.parse('x += 2'), indent=4))
Module(
    body=[
        AugAssign(
            target=Name(id='x', ctx=Store()),
            op=Add(),
            value=Constant(value=2))],
    type_ignores=[])
class ast.Raise(exc, cause)

Оператор raise. exc - это объект исключения, который должен быть поднят, обычно Call или Name, или None для отдельного raise. cause - это необязательная часть для y в raise x from y.

>>> print(ast.dump(ast.parse('raise x from y'), indent=4))
Module(
    body=[
        Raise(
            exc=Name(id='x', ctx=Load()),
            cause=Name(id='y', ctx=Load()))],
    type_ignores=[])
class ast.Assert(test, msg)

Утверждение. test содержит условие, например, узел Compare. msg содержит сообщение об отказе.

>>> print(ast.dump(ast.parse('assert x,y'), indent=4))
Module(
    body=[
        Assert(
            test=Name(id='x', ctx=Load()),
            msg=Name(id='y', ctx=Load()))],
    type_ignores=[])
class ast.Delete(targets)

Представляет собой утверждение del. targets представляет собой список узлов, таких как Name, Attribute или Subscript.

>>> print(ast.dump(ast.parse('del x,y,z'), indent=4))
Module(
    body=[
        Delete(
            targets=[
                Name(id='x', ctx=Del()),
                Name(id='y', ctx=Del()),
                Name(id='z', ctx=Del())])],
    type_ignores=[])
class ast.Pass

Оператор pass.

>>> print(ast.dump(ast.parse('pass'), indent=4))
Module(
    body=[
        Pass()],
    type_ignores=[])

Другие утверждения, которые применимы только внутри функций или циклов, описаны в других разделах.

Импорт

class ast.Import(names)

Оператор импорта. names - это список узлов alias.

>>> print(ast.dump(ast.parse('import x,y,z'), indent=4))
Module(
    body=[
        Import(
            names=[
                alias(name='x'),
                alias(name='y'),
                alias(name='z')])],
    type_ignores=[])
class ast.ImportFrom(module, names, level)

Представляет собой from x import y. module - необработанная строка имени „from“, без ведущих точек, или None для утверждений типа from . import foo. level представляет собой целое число, содержащее уровень относительного импорта (0 означает абсолютный импорт).

>>> print(ast.dump(ast.parse('from y import x,y,z'), indent=4))
Module(
    body=[
        ImportFrom(
            module='y',
            names=[
                alias(name='x'),
                alias(name='y'),
                alias(name='z')],
            level=0)],
    type_ignores=[])
class ast.alias(name, asname)

Оба параметра являются необработанными строками имен. asname может быть None, если должно использоваться обычное имя.

>>> print(ast.dump(ast.parse('from ..foo.bar import a as b, c'), indent=4))
Module(
    body=[
        ImportFrom(
            module='foo.bar',
            names=[
                alias(name='a', asname='b'),
                alias(name='c')],
            level=2)],
    type_ignores=[])

Поток управления

Примечание

Необязательные условия, такие как else, сохраняются в виде пустого списка, если они отсутствуют.

class ast.If(test, body, orelse)

Утверждение if. test содержит один узел, например, узел Compare. body и orelse содержат по списку узлов.

Клаузы elif не имеют специального представления в AST, а появляются как дополнительные узлы If внутри секции orelse предыдущей.

>>> print(ast.dump(ast.parse("""
... if x:
...    ...
... elif y:
...    ...
... else:
...    ...
... """), indent=4))
Module(
    body=[
        If(
            test=Name(id='x', ctx=Load()),
            body=[
                Expr(
                    value=Constant(value=Ellipsis))],
            orelse=[
                If(
                    test=Name(id='y', ctx=Load()),
                    body=[
                        Expr(
                            value=Constant(value=Ellipsis))],
                    orelse=[
                        Expr(
                            value=Constant(value=Ellipsis))])])],
    type_ignores=[])
class ast.For(target, iter, body, orelse, type_comment)

Цикл for. target содержит переменную(ые), которой присваивается цикл, в виде одного узла Name, Tuple или List. iter содержит элемент, по которому будет выполняться цикл, опять же в виде одного узла. body и orelse содержат списки узлов для выполнения. Узлы в orelse выполняются, если цикл завершается нормально, а не через оператор break.

type_comment

type_comment - необязательная строка с аннотацией типа в качестве комментария.

>>> print(ast.dump(ast.parse("""
... for x in y:
...     ...
... else:
...     ...
... """), indent=4))
Module(
    body=[
        For(
            target=Name(id='x', ctx=Store()),
            iter=Name(id='y', ctx=Load()),
            body=[
                Expr(
                    value=Constant(value=Ellipsis))],
            orelse=[
                Expr(
                    value=Constant(value=Ellipsis))])],
    type_ignores=[])
class ast.While(test, body, orelse)

Цикл while. test содержит условие, например, узел Compare.

>> print(ast.dump(ast.parse("""
... while x:
...    ...
... else:
...    ...
... """), indent=4))
Module(
    body=[
        While(
            test=Name(id='x', ctx=Load()),
            body=[
                Expr(
                    value=Constant(value=Ellipsis))],
            orelse=[
                Expr(
                    value=Constant(value=Ellipsis))])],
    type_ignores=[])
class ast.Break
class ast.Continue

Утверждения break и continue.

>>> print(ast.dump(ast.parse("""\
... for a in b:
...     if a > 5:
...         break
...     else:
...         continue
...
... """), indent=4))
Module(
    body=[
        For(
            target=Name(id='a', ctx=Store()),
            iter=Name(id='b', ctx=Load()),
            body=[
                If(
                    test=Compare(
                        left=Name(id='a', ctx=Load()),
                        ops=[
                            Gt()],
                        comparators=[
                            Constant(value=5)]),
                    body=[
                        Break()],
                    orelse=[
                        Continue()])],
            orelse=[])],
    type_ignores=[])
class ast.Try(body, handlers, orelse, finalbody)

try блоков. Все атрибуты представляют собой список узлов для выполнения, за исключением handlers, который является списком узлов ExceptHandler.

>>> print(ast.dump(ast.parse("""
... try:
...    ...
... except Exception:
...    ...
... except OtherException as e:
...    ...
... else:
...    ...
... finally:
...    ...
... """), indent=4))
Module(
    body=[
        Try(
            body=[
                Expr(
                    value=Constant(value=Ellipsis))],
            handlers=[
                ExceptHandler(
                    type=Name(id='Exception', ctx=Load()),
                    body=[
                        Expr(
                            value=Constant(value=Ellipsis))]),
                ExceptHandler(
                    type=Name(id='OtherException', ctx=Load()),
                    name='e',
                    body=[
                        Expr(
                            value=Constant(value=Ellipsis))])],
            orelse=[
                Expr(
                    value=Constant(value=Ellipsis))],
            finalbody=[
                Expr(
                    value=Constant(value=Ellipsis))])],
    type_ignores=[])
class ast.ExceptHandler(type, name, body)

Одиночная оговорка except. type - это тип исключения, которому оно будет соответствовать, обычно узел Name (или None для всеобъемлющей клаузулы except:). name - необработанная строка для имени, в котором будет храниться исключение, или None, если в оговорке нет as foo. body - это список узлов.

>>> print(ast.dump(ast.parse("""\
... try:
...     a + 1
... except TypeError:
...     pass
... """), indent=4))
Module(
    body=[
        Try(
            body=[
                Expr(
                    value=BinOp(
                        left=Name(id='a', ctx=Load()),
                        op=Add(),
                        right=Constant(value=1)))],
            handlers=[
                ExceptHandler(
                    type=Name(id='TypeError', ctx=Load()),
                    body=[
                        Pass()])],
            orelse=[],
            finalbody=[])],
    type_ignores=[])
class ast.With(items, body, type_comment)

Блок with. items - это список узлов withitem, представляющих менеджеры контекста, а body - это блок с отступом внутри контекста.

type_comment

type_comment - необязательная строка с аннотацией типа в качестве комментария.

class ast.withitem(context_expr, optional_vars)

Одиночный менеджер контекста в блоке with. context_expr - это менеджер контекста, часто узел Call. optional_vars - это Name, Tuple или List для части as foo, или None, если она не используется.

>>> print(ast.dump(ast.parse("""\
... with a as b, c as d:
...    something(b, d)
... """), indent=4))
Module(
    body=[
        With(
            items=[
                withitem(
                    context_expr=Name(id='a', ctx=Load()),
                    optional_vars=Name(id='b', ctx=Store())),
                withitem(
                    context_expr=Name(id='c', ctx=Load()),
                    optional_vars=Name(id='d', ctx=Store()))],
            body=[
                Expr(
                    value=Call(
                        func=Name(id='something', ctx=Load()),
                        args=[
                            Name(id='b', ctx=Load()),
                            Name(id='d', ctx=Load())],
                        keywords=[]))])],
    type_ignores=[])

Соответствие шаблонов

class ast.Match(subject, cases)

Утверждение match. subject содержит субъект сопоставления (объект, который сопоставляется со случаями), а cases содержит итерацию узлов match_case с различными случаями.

class ast.match_case(pattern, guard, body)

Одиночный шаблон case в операторе match. pattern содержит шаблон соответствия, с которым будет сопоставлен объект. Обратите внимание, что узлы AST, создаваемые для шаблонов, отличаются от узлов, создаваемых для выражений, даже если они имеют одинаковый синтаксис.

Атрибут guard содержит выражение, которое будет оценено, если шаблон соответствует субъекту.

body содержит список узлов, которые будут выполняться, если шаблон совпадает и результат оценки защитного выражения равен true.

>>> print(ast.dump(ast.parse("""
... match x:
...     case [x] if x>0:
...         ...
...     case tuple():
...         ...
... """), indent=4))
Module(
    body=[
        Match(
            subject=Name(id='x', ctx=Load()),
            cases=[
                match_case(
                    pattern=MatchSequence(
                        patterns=[
                            MatchAs(name='x')]),
                    guard=Compare(
                        left=Name(id='x', ctx=Load()),
                        ops=[
                            Gt()],
                        comparators=[
                            Constant(value=0)]),
                    body=[
                        Expr(
                            value=Constant(value=Ellipsis))]),
                match_case(
                    pattern=MatchClass(
                        cls=Name(id='tuple', ctx=Load()),
                        patterns=[],
                        kwd_attrs=[],
                        kwd_patterns=[]),
                    body=[
                        Expr(
                            value=Constant(value=Ellipsis))])])],
    type_ignores=[])
class ast.MatchValue(value)

Литерал соответствия или шаблон значения, который сравнивает по равенству. value является узлом выражения. Допустимые узлы значений ограничены, как описано в документации по оператору match. Шаблон успешный, если объект совпадения равен оцениваемому значению.

>>> print(ast.dump(ast.parse("""
... match x:
...     case "Relevant":
...         ...
... """), indent=4))
Module(
    body=[
        Match(
            subject=Name(id='x', ctx=Load()),
            cases=[
                match_case(
                    pattern=MatchValue(
                        value=Constant(value='Relevant')),
                    body=[
                        Expr(
                            value=Constant(value=Ellipsis))])])],
    type_ignores=[])
class ast.MatchSingleton(value)

Буквальный шаблон совпадения, который сравнивает по идентичности. value - это синглтон, с которым производится сравнение: None, True или False. Этот шаблон успешный, если объектом сравнения является данная константа.

>>> print(ast.dump(ast.parse("""
... match x:
...     case None:
...         ...
... """), indent=4))
Module(
    body=[
        Match(
            subject=Name(id='x', ctx=Load()),
            cases=[
                match_case(
                    pattern=MatchSingleton(value=None),
                    body=[
                        Expr(
                            value=Constant(value=Ellipsis))])])],
    type_ignores=[])
class ast.MatchSequence(patterns)

Шаблон последовательности сопоставления. patterns содержит шаблоны, которые будут сопоставлены с элементами субъекта, если субъект является последовательностью. Сопоставляет последовательность переменной длины, если один из подшаблонов является узлом MatchStar, в противном случае сопоставляет последовательность фиксированной длины.

>>> print(ast.dump(ast.parse("""
... match x:
...     case [1, 2]:
...         ...
... """), indent=4))
Module(
    body=[
        Match(
            subject=Name(id='x', ctx=Load()),
            cases=[
                match_case(
                    pattern=MatchSequence(
                        patterns=[
                            MatchValue(
                                value=Constant(value=1)),
                            MatchValue(
                                value=Constant(value=2))]),
                    body=[
                        Expr(
                            value=Constant(value=Ellipsis))])])],
    type_ignores=[])
class ast.MatchStar(name)

Сопоставляет оставшуюся часть последовательности в шаблоне последовательности переменной длины. Если name не является None, то при успешном выполнении общего шаблона последовательности к этому имени привязывается список, содержащий оставшиеся элементы последовательности.

>>> print(ast.dump(ast.parse("""
... match x:
...     case [1, 2, *rest]:
...         ...
...     case [*_]:
...         ...
... """), indent=4))
Module(
    body=[
        Match(
            subject=Name(id='x', ctx=Load()),
            cases=[
                match_case(
                    pattern=MatchSequence(
                        patterns=[
                            MatchValue(
                                value=Constant(value=1)),
                            MatchValue(
                                value=Constant(value=2)),
                            MatchStar(name='rest')]),
                    body=[
                        Expr(
                            value=Constant(value=Ellipsis))]),
                match_case(
                    pattern=MatchSequence(
                        patterns=[
                            MatchStar()]),
                    body=[
                        Expr(
                            value=Constant(value=Ellipsis))])])],
    type_ignores=[])
class ast.MatchMapping(keys, patterns, rest)

Шаблон сопоставления. keys - это последовательность узлов выражения. patterns - это соответствующая последовательность узлов шаблона. rest - необязательное имя, которое может быть указано для захвата оставшихся элементов отображения. Допустимые ключевые выражения ограничены, как описано в документации по оператору соответствия.

Этот шаблон успешный, если объект является отображением, все оцененные ключевые выражения присутствуют в отображении, и значение, соответствующее каждому ключу, соответствует соответствующему подшаблону. Если rest не является None, то в случае успеха всего шаблона отображения к этому имени привязывается dict, содержащий остальные элементы отображения.

>>> print(ast.dump(ast.parse("""
... match x:
...     case {1: _, 2: _}:
...         ...
...     case {**rest}:
...         ...
... """), indent=4))
Module(
    body=[
        Match(
            subject=Name(id='x', ctx=Load()),
            cases=[
                match_case(
                    pattern=MatchMapping(
                        keys=[
                            Constant(value=1),
                            Constant(value=2)],
                        patterns=[
                            MatchAs(),
                            MatchAs()]),
                    body=[
                        Expr(
                            value=Constant(value=Ellipsis))]),
                match_case(
                    pattern=MatchMapping(keys=[], patterns=[], rest='rest'),
                    body=[
                        Expr(
                            value=Constant(value=Ellipsis))])])],
    type_ignores=[])
class ast.MatchClass(cls, patterns, kwd_attrs, kwd_patterns)

Шаблон класса соответствия. cls - выражение, задающее номинальный класс для сопоставления. patterns - последовательность узлов шаблона для сопоставления с определенной классом последовательностью атрибутов сопоставления шаблона. kwd_attrs - последовательность дополнительных атрибутов для сопоставления (указываются как аргументы ключевых слов в шаблоне класса), kwd_patterns - соответствующие шаблоны (указываются как значения ключевых слов в шаблоне класса).

Эта схема успешна, если субъект является экземпляром указанного класса, все позиционные шаблоны соответствуют соответствующим атрибутам, определенным классом, и любые указанные атрибуты ключевых слов соответствуют соответствующему шаблону.

Примечание: классы могут определять свойство, возвращающее self, чтобы сопоставить узел шаблона с сопоставляемым экземпляром. Некоторые встроенные типы также сопоставляются таким образом, как описано в документации по оператору match.

>>> print(ast.dump(ast.parse("""
... match x:
...     case Point2D(0, 0):
...         ...
...     case Point3D(x=0, y=0, z=0):
...         ...
... """), indent=4))
Module(
    body=[
        Match(
            subject=Name(id='x', ctx=Load()),
            cases=[
                match_case(
                    pattern=MatchClass(
                        cls=Name(id='Point2D', ctx=Load()),
                        patterns=[
                            MatchValue(
                                value=Constant(value=0)),
                            MatchValue(
                                value=Constant(value=0))],
                        kwd_attrs=[],
                        kwd_patterns=[]),
                    body=[
                        Expr(
                            value=Constant(value=Ellipsis))]),
                match_case(
                    pattern=MatchClass(
                        cls=Name(id='Point3D', ctx=Load()),
                        patterns=[],
                        kwd_attrs=[
                            'x',
                            'y',
                            'z'],
                        kwd_patterns=[
                            MatchValue(
                                value=Constant(value=0)),
                            MatchValue(
                                value=Constant(value=0)),
                            MatchValue(
                                value=Constant(value=0))]),
                    body=[
                        Expr(
                            value=Constant(value=Ellipsis))])])],
    type_ignores=[])
class ast.MatchAs(pattern, name)

Соответствие «как шаблон», шаблон захвата или шаблон подстановочного знака. pattern содержит шаблон соответствия, по которому будет сопоставлен объект. Если шаблон None, узел представляет собой шаблон захвата (т.е. голое имя) и всегда будет успешным.

Атрибут name содержит имя, которое будет связано в случае успеха шаблона. Если name является None, pattern также должен быть None, а узел представляет собой шаблон подстановочного знака.

>>> print(ast.dump(ast.parse("""
... match x:
...     case [x] as y:
...         ...
...     case _:
...         ...
... """), indent=4))
Module(
    body=[
        Match(
            subject=Name(id='x', ctx=Load()),
            cases=[
                match_case(
                    pattern=MatchAs(
                        pattern=MatchSequence(
                            patterns=[
                                MatchAs(name='x')]),
                        name='y'),
                    body=[
                        Expr(
                            value=Constant(value=Ellipsis))]),
                match_case(
                    pattern=MatchAs(),
                    body=[
                        Expr(
                            value=Constant(value=Ellipsis))])])],
    type_ignores=[])
class ast.MatchOr(patterns)

Соответствие «или-шаблон». Шаблон «или» поочередно сопоставляет каждый из своих подшаблонов с объектом, пока один из них не окажется успешным. После этого считается, что шаблон «или» достиг успеха. Если ни один из подшаблонов не достиг успеха, то or-шаблон не работает. Атрибут patterns содержит список узлов шаблона соответствия, которые будут сопоставлены с объектом.

>>> print(ast.dump(ast.parse("""
... match x:
...     case [x] | (y):
...         ...
... """), indent=4))
Module(
    body=[
        Match(
            subject=Name(id='x', ctx=Load()),
            cases=[
                match_case(
                    pattern=MatchOr(
                        patterns=[
                            MatchSequence(
                                patterns=[
                                    MatchAs(name='x')]),
                            MatchAs(name='y')]),
                    body=[
                        Expr(
                            value=Constant(value=Ellipsis))])])],
    type_ignores=[])

Определения функций и классов

class ast.FunctionDef(name, args, body, decorator_list, returns, type_comment)

Определение функции.

  • name - необработанная строка имени функции.

  • args является узлом arguments.

  • body - это список узлов внутри функции.

  • decorator_list - это список декораторов, которые будут применены, хранятся сначала крайние (т.е. первый в списке будет применен последним).

  • returns - это аннотация возврата.

type_comment

type_comment - необязательная строка с аннотацией типа в качестве комментария.

class ast.Lambda(args, body)

lambda - это минимальное определение функции, которое может быть использовано внутри выражения. В отличие от FunctionDef, body содержит один узел.

>>> print(ast.dump(ast.parse('lambda x,y: ...'), indent=4))
Module(
    body=[
        Expr(
            value=Lambda(
                args=arguments(
                    posonlyargs=[],
                    args=[
                        arg(arg='x'),
                        arg(arg='y')],
                    kwonlyargs=[],
                    kw_defaults=[],
                    defaults=[]),
                body=Constant(value=Ellipsis)))],
    type_ignores=[])
class ast.arguments(posonlyargs, args, vararg, kwonlyargs, kw_defaults, kwarg, defaults)

Аргументы для функции.

  • posonlyargs, args и kwonlyargs являются списками узлов arg.

  • vararg и kwarg являются одиночными узлами arg, ссылающимися на параметры *args, **kwargs.

  • kw_defaults - это список значений по умолчанию для аргументов, относящихся только к ключевым словам. Если одно из них None, то соответствующий аргумент является обязательным.

  • defaults - это список значений по умолчанию для аргументов, которые могут быть переданы позиционно. Если значений по умолчанию меньше, они соответствуют последним n аргументам.

class ast.arg(arg, annotation, type_comment)

Одиночный аргумент в списке. arg - необработанная строка имени аргумента, annotation - его аннотация, например, узел Str или Name.

type_comment

type_comment - необязательная строка с аннотацией типа в качестве комментария

>>> print(ast.dump(ast.parse("""\
... @decorator1
... @decorator2
... def f(a: 'annotation', b=1, c=2, *d, e, f=3, **g) -> 'return annotation':
...     pass
... """), indent=4))
Module(
    body=[
        FunctionDef(
            name='f',
            args=arguments(
                posonlyargs=[],
                args=[
                    arg(
                        arg='a',
                        annotation=Constant(value='annotation')),
                    arg(arg='b'),
                    arg(arg='c')],
                vararg=arg(arg='d'),
                kwonlyargs=[
                    arg(arg='e'),
                    arg(arg='f')],
                kw_defaults=[
                    None,
                    Constant(value=3)],
                kwarg=arg(arg='g'),
                defaults=[
                    Constant(value=1),
                    Constant(value=2)]),
            body=[
                Pass()],
            decorator_list=[
                Name(id='decorator1', ctx=Load()),
                Name(id='decorator2', ctx=Load())],
            returns=Constant(value='return annotation'))],
    type_ignores=[])
class ast.Return(value)

Оператор return.

>>> print(ast.dump(ast.parse('return 4'), indent=4))
Module(
    body=[
        Return(
            value=Constant(value=4))],
    type_ignores=[])
class ast.Yield(value)
class ast.YieldFrom(value)

Выражение yield или yield from. Поскольку это выражения, они должны быть обернуты в узел Expr, если отправленное обратно значение не используется.

>>> print(ast.dump(ast.parse('yield x'), indent=4))
Module(
    body=[
        Expr(
            value=Yield(
                value=Name(id='x', ctx=Load())))],
    type_ignores=[])

>>> print(ast.dump(ast.parse('yield from x'), indent=4))
Module(
    body=[
        Expr(
            value=YieldFrom(
                value=Name(id='x', ctx=Load())))],
    type_ignores=[])
class ast.Global(names)
class ast.Nonlocal(names)

global и nonlocal утверждения. names представляет собой список необработанных строк.

>>> print(ast.dump(ast.parse('global x,y,z'), indent=4))
Module(
    body=[
        Global(
            names=[
                'x',
                'y',
                'z'])],
    type_ignores=[])

>>> print(ast.dump(ast.parse('nonlocal x,y,z'), indent=4))
Module(
    body=[
        Nonlocal(
            names=[
                'x',
                'y',
                'z'])],
    type_ignores=[])
class ast.ClassDef(name, bases, keywords, starargs, kwargs, body, decorator_list)

Определение класса.

  • name - необработанная строка для имени класса

  • bases - это список узлов для явно указанных базовых классов.

  • keywords представляет собой список узлов keyword, в основном для „metaclass“. Другие ключевые слова будут переданы в метакласс в соответствии с PEP-3115.

  • starargs и kwargs - это каждый отдельный узел, как в вызове функции. starargs будет расширен для присоединения к списку базовых классов, а kwargs будет передан метаклассу.

  • body - это список узлов, представляющих код внутри определения класса.

  • decorator_list - это список узлов, как в FunctionDef.

>>> print(ast.dump(ast.parse("""\
... @decorator1
... @decorator2
... class Foo(base1, base2, metaclass=meta):
...     pass
... """), indent=4))
Module(
    body=[
        ClassDef(
            name='Foo',
            bases=[
                Name(id='base1', ctx=Load()),
                Name(id='base2', ctx=Load())],
            keywords=[
                keyword(
                    arg='metaclass',
                    value=Name(id='meta', ctx=Load()))],
            body=[
                Pass()],
            decorator_list=[
                Name(id='decorator1', ctx=Load()),
                Name(id='decorator2', ctx=Load())])],
    type_ignores=[])

Асинхронность и ожидание

class ast.AsyncFunctionDef(name, args, body, decorator_list, returns, type_comment)

Определение функции async def. Имеет те же поля, что и FunctionDef.

class ast.Await(value)

Выражение await. value - это то, чего оно ожидает. Действителен только в теле выражения AsyncFunctionDef.

>>> print(ast.dump(ast.parse("""\
... async def f():
...     await other_func()
... """), indent=4))
Module(
    body=[
        AsyncFunctionDef(
            name='f',
            args=arguments(
                posonlyargs=[],
                args=[],
                kwonlyargs=[],
                kw_defaults=[],
                defaults=[]),
            body=[
                Expr(
                    value=Await(
                        value=Call(
                            func=Name(id='other_func', ctx=Load()),
                            args=[],
                            keywords=[])))],
            decorator_list=[])],
    type_ignores=[])
class ast.AsyncFor(target, iter, body, orelse, type_comment)
class ast.AsyncWith(items, body, type_comment)

async for циклы и async with контекстные менеджеры. Они имеют те же поля, что и For и With соответственно. Действительны только в теле AsyncFunctionDef.

Примечание

Когда строка разбирается с помощью ast.parse(), операторные узлы (подклассы ast.operator, ast.unaryop, ast.cmpop, ast.boolop и ast.expr_context) на возвращаемом дереве будут синглтонами. Изменения в одном из них будут отражены во всех остальных вхождениях того же значения (например, ast.Add).

ast Помощники

Помимо классов узлов, модуль ast определяет эти служебные функции и классы для обхода абстрактных синтаксических деревьев:

ast.parse(source, filename='<unknown>', mode='exec', *, type_comments=False, feature_version=None)

Разобрать источник в узел AST. Эквивалентно compile(source, filename, mode, ast.PyCF_ONLY_AST).

Если указано type_comments=True, синтаксический анализатор модифицируется для проверки и возврата комментариев типов, указанных PEP 484 и PEP 526. Это эквивалентно добавлению ast.PyCF_TYPE_COMMENTS к флагам, переданным в compile(). Это сообщит о синтаксических ошибках для неправильно размещенных комментариев типов. Без этого флага комментарии типов будут игнорироваться, а поле type_comment в выбранных узлах AST всегда будет None. Кроме того, расположение комментариев # type: ignore будет возвращаться в виде атрибута type_ignores в Module (иначе это всегда пустой список).

Кроме того, если mode является 'func_type', входной синтаксис модифицируется, чтобы соответствовать PEP 484 «комментариям типа сигнатуры», например, (str, int) -> List[str].

Кроме того, установка feature_version в кортеж (major, minor) приведет к попытке разбора с использованием грамматики этой версии Python. В настоящее время major должно быть равно 3. Например, установка feature_version=(3, 4) позволит использовать async и await в качестве имен переменных. Наименьшая поддерживаемая версия - (3, 4); наибольшая - sys.version_info[0:2].

Если источник содержит нулевой символ (“0“), выдается сообщение ValueError.

Предупреждение

Обратите внимание, что успешный разбор исходного кода в объект AST не гарантирует, что предоставленный исходный код является корректным кодом Python, который может быть выполнен, так как на этапе компиляции могут возникнуть дополнительные исключения SyntaxError. Например, источник return 42 генерирует корректный узел AST для оператора return, но он не может быть скомпилирован сам по себе (он должен находиться внутри узла функции).

В частности, ast.parse() не будет выполнять никаких проверок масштабирования, что делает шаг компиляции.

Предупреждение

Возможно аварийное завершение работы интерпретатора Python с достаточно большой/сложной строкой из-за ограничений глубины стека в AST-компиляторе Python.

Изменено в версии 3.8: Добавлены type_comments, mode='func_type' и feature_version.

ast.unparse(ast_obj)

Разберите объект ast.AST и сгенерируйте строку с кодом, который произведет эквивалентный объект ast.AST, если его разобрать обратно с помощью ast.parse().

Предупреждение

Произведенная строка кода не обязательно будет равна исходному коду, который сгенерировал объект ast.AST (без каких-либо оптимизаций компилятора, таких как константные кортежи/розетки).

Предупреждение

Попытка разобрать очень сложное выражение приведет к результату RecursionError.

Добавлено в версии 3.9.

ast.literal_eval(node_or_string)

Безопасная оценка узла выражения или строки, содержащей литерал Python или контейнерное отображение. Предоставленная строка или узел могут состоять только из следующих буквенных структур Python: строки, байты, числа, кортежи, списки, dicts, множества, булевы, None и Ellipsis.

Это можно использовать для безопасной оценки строк, содержащих значения Python из ненадежных источников без необходимости самостоятельно разбирать значения. Он не способен оценивать произвольно сложные выражения, например, с операторами или индексацией.

Предупреждение

Возможно аварийное завершение работы интерпретатора Python с достаточно большой/сложной строкой из-за ограничений глубины стека в AST-компиляторе Python.

В зависимости от искаженного ввода он может вызвать ValueError, TypeError, SyntaxError, MemoryError и RecursionError.

Изменено в версии 3.2: Теперь позволяет использовать байты и литералы множеств.

Изменено в версии 3.9: Теперь поддерживается создание пустых множеств с помощью 'set()'.

Изменено в версии 3.10: При вводе строк ведущие пробелы и табуляции теперь удаляются.

ast.get_docstring(node, clean=True)

Возвращает docstring данного node (который должен быть узлом FunctionDef, AsyncFunctionDef, ClassDef или Module), или None, если он не имеет docstring. Если clean равно true, очистите отступы doc-строки с помощью inspect.cleandoc().

Изменено в версии 3.5: AsyncFunctionDef теперь поддерживается.

ast.get_source_segment(source, node, *, padded=False)

Получить сегмент исходного кода источника, который породил узел. Если некоторая информация о местоположении (lineno, end_lineno, col_offset или end_col_offset) отсутствует, возвращается None.

Если padded равно True, то первая строка многострочного оператора будет заполнена пробелами в соответствии с ее исходным положением.

Добавлено в версии 3.8.

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, end_lineno и end_col_offset) из old_node в new_node, если это возможно, и верните new_node.

ast.iter_fields(node)

Выдает кортеж (fieldname, value) для каждого поля в node._fields, которое присутствует на узле.

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), который позволяет вносить изменения.

Не рекомендуется, начиная с версии 3.8: Методы visit_Num(), visit_Str(), visit_Bytes(), visit_NameConstant() и visit_Ellipsis() теперь устарели и не будут вызываться в будущих версиях Python. Добавьте метод visit_Constant() для обработки всех константных узлов.

class ast.NodeTransformer

Подкласс NodeVisitor, который обходит дерево абстрактного синтаксиса и позволяет модифицировать узлы.

NodeTransformer пройдет по AST и использует возвращаемое значение методов посетителей для замены или удаления старого узла. Если возвращаемое значение метода посетителя равно None, узел будет удален из своего местоположения, в противном случае он будет заменен возвращаемым значением. Возвращаемое значение может быть исходным узлом, в этом случае замена не происходит.

Вот пример трансформатора, который переписывает все вхождения поиска имени (foo) в data['foo']:

class RewriteName(NodeTransformer):

    def visit_Name(self, node):
        return Subscript(
            value=Name(id='data', ctx=Load()),
            slice=Constant(value=node.id),
            ctx=node.ctx
        )

Помните, что если узел, с которым вы работаете, имеет дочерние узлы, вы должны либо преобразовать дочерние узлы самостоятельно, либо сначала вызвать метод generic_visit() для узла.

Для узлов, которые были частью коллекции утверждений (это относится ко всем узлам утверждений), посетитель может также вернуть список узлов, а не только один узел.

Если NodeTransformer вводит новые узлы (которые не были частью исходного дерева) без предоставления им информации о расположении (например, lineno), fix_missing_locations() должен быть вызван с новым поддеревом для пересчета информации о расположении:

tree = ast.parse('foo', mode='eval')
new_tree = fix_missing_locations(RewriteName().visit(tree))

Обычно вы используете трансформатор следующим образом:

node = YourTransformer().visit(node)
ast.dump(node, annotate_fields=True, include_attributes=False, *, indent=None)

Возвращает форматированный дамп дерева в node. Это в основном полезно для отладки. Если annotate_fields равно true (по умолчанию), в возвращаемой строке будут показаны имена и значения полей. Если annotate_fields равно false, результирующая строка будет более компактной за счет исключения однозначных имен полей. Такие атрибуты, как номера строк и смещения столбцов, по умолчанию не передаются в дамп. Если это необходимо, include_attributes можно установить в true.

Если indent - неотрицательное целое число или строка, то дерево будет напечатано с этим уровнем отступа. Уровень отступа 0, отрицательный, или "" будет вставлять только новые строки. None (по умолчанию) выбирает однострочное представление. При использовании целого положительного числа отступ отступает на столько-то пробелов за уровень. Если indent является строкой (например, "\t"), то эта строка используется для отступа на каждом уровне.

Изменено в версии 3.9: Добавлена опция indent.

Флаги компилятора

Следующие флаги могут быть переданы в compile() для изменения влияния на компиляцию программы:

ast.PyCF_ALLOW_TOP_LEVEL_AWAIT

Включает поддержку верхнего уровня await, async for, async with и асинхронных пониманий.

Добавлено в версии 3.8.

ast.PyCF_ONLY_AST

Генерирует и возвращает абстрактное дерево синтаксиса вместо того, чтобы возвращать объект скомпилированного кода.

ast.PyCF_TYPE_COMMENTS

Включает поддержку комментариев типа PEP 484 и PEP 526 (# type: <type>, # type: ignore <stuff>).

Добавлено в версии 3.8.

Использование командной строки

Добавлено в версии 3.9.

Модуль ast может быть выполнен как сценарий из командной строки. Это очень просто:

python -m ast [-m <mode>] [-a] [infile]

Принимаются следующие варианты:

-h, --help

Покажите сообщение справки и выйдите.

-m <mode>
--mode <mode>

Укажите, какой тип кода должен быть скомпилирован, подобно аргументу mode в parse().

--no-type-comments

Не разбирайте комментарии типа.

-a, --include-attributes

Включите такие атрибуты, как номера строк и смещения колонок.

-i <indent>
--indent <indent>

Отступы узлов в AST (количество пробелов).

Если указано infile, его содержимое разбирается на AST и выводится на stdout. В противном случае содержимое считывается из stdin.

См.также

Green Tree Snakes, внешний ресурс документации, содержит хорошие подробности о работе с АСТ Python.

ASTTokens аннотирует АСТ Python с указанием позиций лексем и текста в исходном коде, который их породил. Это полезно для инструментов, которые выполняют преобразования исходного кода.

leoAst.py объединяет представления программ на основе лексем и деревьев разбора python, вставляя двусторонние связи между лексемами и узлами ast.

LibCST разбирает код в виде конкретного синтаксического дерева, которое выглядит как дерево ast и сохраняет все детали форматирования. Это полезно для создания приложений автоматического рефакторинга (codemod) и линтеров.

Parso - это парсер Python, который поддерживает восстановление ошибок и парсинг по кругу для различных версий Python (в нескольких версиях Python). Parso также способен перечислить множество синтаксических ошибок в вашем файле python.

Вернуться на верх