ast.rst 9.38 KB

:mod:`ast` --- Abstract Syntax Trees

Source code: :source:`Lib/ast.py`


The :mod:`ast` module helps Python applications to process trees of the Python abstract syntax grammar. The abstract syntax itself might change with each Python release; this module helps to find out programmatically what the current grammar looks like.

An abstract syntax tree can be generated by passing :data:`ast.PyCF_ONLY_AST` as a flag to the :func:`compile` built-in function, or using the :func:`parse` helper provided in this module. The result will be a tree of objects whose classes all inherit from :class:`ast.AST`. An abstract syntax tree can be compiled into a Python code object using the built-in :func:`compile` function.

Node classes

This is the base of all AST node classes. The actual node classes are derived from the :file:`Parser/Python.asdl` file, which is reproduced :ref:`below <abstract-grammar>`. They are defined in the :mod:`_ast` C module and re-exported in :mod:`ast`.

There is one class defined for each left-hand side symbol in the abstract grammar (for example, :class:`ast.stmt` or :class:`ast.expr`). In addition, there is one class defined for each constructor on the right-hand side; these classes inherit from the classes for the left-hand side trees. For example, :class:`ast.BinOp` inherits from :class:`ast.expr`. For production rules with alternatives (aka "sums"), the left-hand side class is abstract: only instances of specific constructor nodes are ever created.

The constructor of a class :class:`ast.T` parses its arguments as follows:

  • If there are positional arguments, there must be as many as there are items in :attr:`T._fields`; they will be assigned as attributes of these names.
  • If there are keyword arguments, they will set the attributes of the same names to the given values.

For example, to create and populate an :class:`ast.UnaryOp` node, you could use

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

or the more compact

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

Abstract Grammar

The abstract grammar is currently defined as follows:

:mod:`ast` Helpers

Apart from the node classes, :mod:`ast` module defines these utility functions and classes for traversing abstract syntax trees:

A node visitor base class that walks the abstract syntax tree and calls a visitor function for every node found. This function may return a value which is forwarded by the :meth:`visit` method.

This class is meant to be subclassed, with the subclass adding visitor methods.

Don't use the :class:`NodeVisitor` if you want to apply changes to nodes during traversal. For this a special visitor exists (:class:`NodeTransformer`) that allows modifications.

A :class:`NodeVisitor` subclass that walks the abstract syntax tree and allows modification of nodes.

The :class:`NodeTransformer` will walk the AST and use the return value of the visitor methods to replace or remove the old node. If the return value of the visitor method is None, the node will be removed from its location, otherwise it is replaced with the return value. The return value may be the original node in which case no replacement takes place.

Here is an example transformer that rewrites all occurrences of name lookups (foo) to 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)

Keep in mind that if the node you're operating on has child nodes you must either transform the child nodes yourself or call the :meth:`generic_visit` method for the node first.

For nodes that were part of a collection of statements (that applies to all statement nodes), the visitor may also return a list of nodes rather than just a single node.

Usually you use the transformer like this:

node = YourTransformer().visit(node)