承上篇,終究不宜每次剪貼 Green Tree Snakes 小工具耶?
故將之存成檔案︰
rock64@rock64:~/prg$ more gts.py from ast import * def dump(node, annotate_fields=True, include_attributes=False, indent=' '): """ Return a formatted dump of the tree in *node*. This is mainly useful for debugging purposes. The returned string will show the names and the values for fields. This makes the code impossible to evaluate, so if evaluation is wanted *annotate_fields* must be set to False. Attributes such as line numbers and column offsets are not dumped by default. If this is wanted, *include_attributes* can be set to True. """ def _format(node, level=0): if isinstance(node, AST): fields = [(a, _format(b, level)) for a, b in iter_fields(node)] if include_attributes and node._attributes: fields.extend([(a, _format(getattr(node, a), level)) for a in node._attributes]) return ''.join([ node.__class__.__name__, '(', ', '.join(('%s=%s' % field for field in fields) if annotate_fields else (b for a, b in fields)), ')']) elif isinstance(node, list): lines = ['['] lines.extend((indent * (level + 2) + _format(x, level + 2) + ',' for x in node)) if len(lines) > 1: lines.append(indent * (level + 1) + ']') else: lines[-1] += ']' return '\n'.join(lines) return repr(node) if not isinstance(node, AST): raise TypeError('expected AST, got %r' % node.__class__.__name__) return _format(node) def parseprint(code, filename="<string>", mode="exec", **kwargs): """Parse some code from a string and pretty-print it.""" node = parse(code, mode=mode) # An ode to the code print(dump(node, **kwargs)) from IPython.core.magic import (register_line_magic, register_cell_magic) @register_cell_magic def dump_ast(line, cell): """Parse the code in the cell, and pretty-print the AST.""" parseprint(cell)
直接執行引用也!
藉著漂亮列印以及圖示︰
讓我們親近了那顆『樹』,或想漫步於其間乎??
Working on the Tree
ast.NodeVisitor
is the primary tool for ‘scanning’ the tree. To use it, subclass it and override methods visit_Foo
, corresponding to the node classes (see Meet the Nodes).
For example, this visitor will print the names of any functions defined in the given code, including methods and functions defined within other functions:
class FuncLister(ast.NodeVisitor): def visit_FunctionDef(self, node): print(node.name) self.generic_visit(node) FuncLister().visit(tree)
Note
If you want child nodes to be visited, remember to call self.generic_visit(node)
in the methods you override.
千萬不要被上面言簡意賅文字嚇到!!
只是需要讀幾行 ast.py
class NodeVisitor(object): """ 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 `visit` method. This class is meant to be subclassed, with the subclass adding visitor methods. Per default the visitor functions for the nodes are ``'visit_'`` + class name of the node. So a `TryFinally` node visit function would be `visit_TryFinally`. This behavior can be changed by overriding the `visit` method. If no visitor function exists for a node (return value `None`) the `generic_visit` visitor is used instead. Don't use the `NodeVisitor` if you want to apply changes to nodes during traversing. For this a special visitor exists (`NodeTransformer`) that allows modifications. """ 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 field, value in iter_fields(node): if isinstance(value, list): for item in value: if isinstance(item, AST): self.visit(item) elif isinstance(value, AST): self.visit(value)
認識就行的哩☆