我正在分析python代码生成的“fun and profit”的AST,我希望有更多的图形比“ast.dump”更真实地看到AST生成的图形。python ast点图
理论上已经是一棵树,所以创建一个图不应该太难,但我不明白我该怎么做。
ast.walk似乎与BFS战略,行走,visitX方法,我真的不能看到父母或我似乎还没有找到一种方法来创建一个图形...
似乎唯一的办法就是编写我自己的DFS漫游功能,这是否有意义?
我正在分析python代码生成的“fun and profit”的AST,我希望有更多的图形比“ast.dump”更真实地看到AST生成的图形。python ast点图
理论上已经是一棵树,所以创建一个图不应该太难,但我不明白我该怎么做。
ast.walk似乎与BFS战略,行走,visitX方法,我真的不能看到父母或我似乎还没有找到一种方法来创建一个图形...
似乎唯一的办法就是编写我自己的DFS漫游功能,这是否有意义?
如果你看ast.NodeVisitor,这是一个相当微不足道的类。您可以将其子类化,或者只是将其步行策略重新实现为任何您需要的。例如,当访问节点时保持对父节点的引用非常简单,只需添加一个visit
方法,该方法也接受父节点作为参数,并从您自己的generic_visit
中传递该方法。
P.S.顺便说一句,看起来NodeVisitor.generic_visit
实现了DFS,所以你所要做的就是添加父节点传递。
好极了,它的工作原理,它是非常简单的
class AstGraphGenerator(object):
def __init__(self):
self.graph = defaultdict(lambda: [])
def __str__(self):
return str(self.graph)
def visit(self, node):
"""Visit a node."""
method = 'visit_' + node.__class__.__name__
visitor = getattr(self, method, self.generic_visit)
return visitor(node)
def generic_visit(self, node):
"""Called if no explicit visitor function exists for a node."""
for _, value in ast.iter_fields(node):
if isinstance(value, list):
for item in value:
if isinstance(item, ast.AST):
self.visit(item)
elif isinstance(value, ast.AST):
self.graph[type(node)].append(type(value))
self.visit(value)
所以它的同正常NodeVisitor,但我有一个defaultdict,我添加了每个儿子节点的类型。 然后我将这个字典传递给pygraphviz.AGraph,我得到了不错的结果。
唯一的问题是类型不会说太多,但另一方面使用ast.dump()方式太冗长。
最好的事情是获得每个节点的实际源代码,这可能吗?
编辑:现在它好多了,我传入构造函数也源代码,我尝试获取代码行,如果可能的话,否则只是打印出类型。
class AstGraphGenerator(object):
def __init__(self, source):
self.graph = defaultdict(lambda: [])
self.source = source # lines of the source code
def __str__(self):
return str(self.graph)
def _getid(self, node):
try:
lineno = node.lineno - 1
return "%s: %s" % (type(node), self.source[lineno].strip())
except AttributeError:
return type(node)
def visit(self, node):
"""Visit a node."""
method = 'visit_' + node.__class__.__name__
visitor = getattr(self, method, self.generic_visit)
return visitor(node)
def generic_visit(self, node):
"""Called if no explicit visitor function exists for a node."""
for _, value in ast.iter_fields(node):
if isinstance(value, list):
for item in value:
if isinstance(item, ast.AST):
self.visit(item)
elif isinstance(value, ast.AST):
node_source = self._getid(node)
value_source = self._getid(value)
self.graph[node_source].append(value_source)
# self.graph[type(node)].append(type(value))
self.visit(value)
是的,你是对的是一个非常简单的实现,我首先想到的是我不得不检查所有可能的情况,但实际上检查,如果它是一个列表或者不已经足够在树中走..谢谢很多 –