[英]Python ast to dot graph
我正在分析python代码生成的AST“有趣和利润”,我希望有一些比“ast.dump”更具图形性的东西来实际看到生成的AST。
理论上已经是一棵树了,所以创建一个图表应该不会太难,但我不明白我是怎么做到的。
ast.walk似乎走了一个BFS策略,而visitX方法我真的看不到父或我似乎没有找到创建图的方法...
似乎唯一的方法就是编写自己的DFS walk函数,它是否有意义?
如果你看一下ast.NodeVisitor,它是一个相当简单的类。 您既可以将其子类化,也可以将其步行策略重新实现为您需要的任何内容。 例如,在访问节点时保持对父节点的引用非常简单,只需添加一个也接受父节点作为参数的visit
方法,并从你自己的generic_visit
传递它。
PS顺便说一下,似乎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)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.