Можно ли дважды посетить узлы в Python AST с помощью ast.NodeVisitor или изменить порядок обхода? - PullRequest
2 голосов
/ 04 апреля 2011

NodeVisitor сначала проходит глубину AST и посещает каждый узел только один раз при входе.Поэтому сделать с этим что-то серьезное проблематично.Можно ли изменить его поведение по умолчанию?

Ответы [ 2 ]

8 голосов
/ 02 февраля 2013

Может быть, кому-то будет интересен какой-то набросанный пример, как сделать то, что было предложено DSblizzard, так что послушайте мой пример:

import ast

class RecursiveVisitor(ast.NodeVisitor):
    """ example recursive visitor """

    def recursive(func):
        """ decorator to make visitor work recursive """
        def wrapper(self,node):
            func(self,node)
            for child in ast.iter_child_nodes(node):
                self.visit(child)
        return wrapper

    @recursive
    def visit_Assign(self,node):
        """ visit a Assign node and visits it recursively"""
        print(type(node).__name__)

    @recursive
    def visit_BinOp(self, node):
        """ visit a BinOp node and visits it recursively"""
        print(type(node).__name__)

    @recursive
    def visit_Call(self,node):
        """ visit a Call node and visits it recursively"""
        print(type(node).__name__)

    @recursive
    def visit_Lambda(self,node):
        """ visit a Function node """
        print(type(node).__name__)

    @recursive
    def visit_FunctionDef(self,node):
        """ visit a Function node and visits it recursively"""
        print(type(node).__name__)

    @recursive
    def visit_Module(self,node):
        """ visit a Module node and the visits recursively"""
        pass

    def generic_visit(self,node):
        pass

class SimpleVisitor(ast.NodeVisitor):
    """ simple visitor for comparison """

    def recursive(func):
        """ decorator to make visitor work recursive """
        def wrapper(self,node):
            func(self,node)
            for child in ast.iter_child_nodes(node):
                self.visit(child)
        return wrapper

    def visit_Assign(self,node):
        """ visit a Assign node """
        print(type(node).__name__)

    def visit_BinOp(self, node):
        """ visit a BinOp node """
        print(type(node).__name__)

    def visit_Call(self,node):
        """ visit a Call node """
        print(type(node).__name__)

    def visit_Lambda(self,node):
        """ visit a Function node """
        print(type(node).__name__)

    def visit_FunctionDef(self,node):
        """ visit a Function node """
        print(type(node).__name__)

    @recursive
    def visit_Module(self,node):
        """ visit a Module node and the visits recursively, otherwise you
        wouldn't see anything here"""
        pass

    def generic_visit(self,node):
        pass

# usage example
a = """
b= lambda x: x*5 +5
def hhh(u):
    b=19
    return u*b
m=hhh(9*4+5)
"""

recursive_visitor = RecursiveVisitor()
simple_visitor = SimpleVisitor()
tree = ast.parse(a)
print('\nvisit recursive\n')
recursive_visitor.visit(tree)
print('\nvisit simple\n')
simple_visitor.visit(tree)

Надеюсь, кто-то может найти это полезным.

2 голосов
/ 04 апреля 2011

Неа.Вы должны написать свой собственный посетитель.Рекурсивное посещение всех узлов довольно просто, так что если модуль ast не делает это за вас (и в этом модуле нет ничего, что можно сделать, как вы хотите), это не так уж плохо сделать это самостоятельно.

...