先看这个简单的例子:
http://dongweiming.github.io/python-visitor.html
然后看这个例子:
class Node: pass class UnaryOperator(Node): def __init__(self, operand): self.operand = operand class BinaryOperator(Node): def __init__(self, left, right): self.left = left self.right = right class Add(BinaryOperator): pass class Sub(BinaryOperator): pass class Mul(BinaryOperator): pass class Div(BinaryOperator): pass class Negate(UnaryOperator): pass class Number(Node): def __init__(self, value): self.value = value class NodeVisitor: def visit(self, node): methname = 'visit_' + type(node).__name__ meth = getattr(self, methname, None) if meth is None: meth = self.generic_visit return meth(node) def generic_visit(self, node): raise RuntimeError('No {} method'.format('visit_' + type(node).__name__)) class Evaluator(NodeVisitor): def visit_Number(self, node): return node.value def visit_Add(self, node): return self.visit(node.left) + self.visit(node.right) def visit_Sub(self, node): return self.visit(node.left) - self.visit(node.right) def visit_Mul(self, node): return self.visit(node.left) * self.visit(node.right) def visit_Div(self, node): return self.visit(node.left) / self.visit(node.right) def visit_Negate(self, node): return -node.operand t1 = Sub(Number(3), Number(4)) t2 = Mul(Number(2), t1) t3 = Div(t2, Number(5)) t4 = Add(Number(1), t3) e = Evaluator() print(e.visit(t4))
结果是
0.6
上面也使用了访问者模式。Evaluator是访问者,每次改变改变这里。
1 class Node: 2 pass 3 4 class UnaryOperator(Node): 5 def __init__(self, operand): 6 self.operand = operand 7 8 class BinaryOperator(Node): 9 def __init__(self, left, right): 10 self.left = left 11 self.right = right 12 13 class Add(BinaryOperator): 14 pass 15 16 class Sub(BinaryOperator): 17 pass 18 19 class Mul(BinaryOperator): 20 pass 21 22 class Div(BinaryOperator): 23 pass 24 25 class Negate(UnaryOperator): 26 pass 27 28 class Number(Node): 29 def __init__(self, value): 30 self.value = value 31 32 class NodeVisitor: 33 def visit(self, node): 34 methname = 'visit_' + type(node).__name__ 35 meth = getattr(self, methname, None) 36 if meth is None: 37 meth = self.generic_visit 38 return meth(node) 39 40 def generic_visit(self, node): 41 raise RuntimeError('No {} method'.format('visit_' + type(node).__name__)) 42 43 class StackCode(NodeVisitor): 44 def generate_code(self, node): 45 self.instructions = [] 46 self.visit(node) 47 return self.instructions 48 49 def visit_Number(self, node): 50 self.instructions.append(('PUSH', node.value)) 51 52 def binop(self, node, instruction): 53 self.visit(node.left) 54 self.visit(node.right) 55 self.instructions.append((instruction,)) 56 57 def visit_Add(self, node): 58 self.binop(node, 'ADD') 59 60 def visit_Sub(self, node): 61 self.binop(node, 'SUB') 62 63 def visit_Mul(self, node): 64 self.binop(node, 'MUL') 65 66 def visit_Div(self, node): 67 self.binop(node, 'DIV') 68 69 def unaryop(self, node, instruction): 70 self.visit(node.operand) 71 self.instructions.append((instruction,)) 72 73 def visit_Negate(self, node): 74 self.unaryop(node, 'NEG') 75 76 t1 = Sub(Number(3), Number(4)) 77 t2 = Mul(Number(2), t1) 78 t3 = Div(t2, Number(5)) 79 t4 = Add(Number(1), t3) 80 e = StackCode() 81 print(e.generate_code(t4))
结果是
[('PUSH', 1), ('PUSH', 2), ('PUSH', 3), ('PUSH', 4), ('SUB',), ('MUL',), ('PUSH', 5), ('DIV',), ('ADD',)]