Search code examples
pythonabstract-syntax-tree

Python AST: How to get the children of a node


I am working on Python 2.6.5.

Given a Abstract Syntax Tree, I want to obtain its children.

Most StackOverflow posts discuss ast.NodeVisitor and the methods defined in it: visit(), generic_visit(). However, visit() and generic_visit() do not give the children, rather they directly apply the function recursively on them.

Can someone please write a short code or so to demonstrate it? Does there exist a predefined function in python library for the same?


Solution

  • The attaributes containing the node's children depend on the type of syntax the node represents. Every node class also has a special _fields attribute, that lists the attribute names for the child nodes that class has. For instance,

    >>> ast.parse('5+a')
    <_ast.Module object at 0x02C1F730>
    >>> ast.parse('5+a').body
    [<_ast.Expr object at 0x02C1FF50>]
    >>> ast.parse('5+a').body[0]
    <_ast.Expr object at 0x02C1FBF0>
    >>> ast.parse('5+a').body[0]._fields
    ('value',)
    >>> ast.parse('5+a').body[0].value
    <_ast.BinOp object at 0x02C1FF90>
    >>> ast.parse('5+a').body[0].value._fields
    ('left', 'op', 'right')
    >>> ast.parse('5+a').body[0].value.left
    <_ast.Num object at 0x02C1FB70>
    

    and so on.

    Edit, to clarify what's going on

    Before going any further, take a glance at the CPython Abstract Grammar

    Consider:

    >>> type(ast.parse('5+a'))
    <class '_ast.Module'>
    

    In fact, if you look at the grammar, the first production rule is for Module. It appears to take a sequence of statements, as an argument called body.

    >>> ast.parse('5+a')._fields
    ('body',)
    >>> ast.parse('5+a').body
    [<_ast.Expr object at 0x02E965B0>]
    

    The _fields attribute of the AST is just "body", and the body attribute is a sequence of AST nodes. Back to the grammar, looking in the production rules for stmt, we see that Expr takes a single expr, named value

    >>> ast.parse('5+a').body[0].value
    <_ast.BinOp object at 0x02E96330>
    

    If we look up the definition for BinOp, we see that it takes 3 different arguments, left, op and right. You should be able to proceed from there, I hope.