============================ 8.21 å®žçŽ°è®¿é—®è€…æ¨¡å¼ ============================ ---------- 问题 ---------- ä½ è¦å¤„ç†ç”±å¤§é‡ä¸åŒç±»åž‹çš„对象组æˆçš„夿‚æ•°æ®ç»“构,æ¯ä¸€ä¸ªå¯¹è±¡éƒ½éœ€è¦è¿›è¡Œä¸åŒçš„处ç†ã€‚ 比如,éåŽ†ä¸€ä¸ªæ ‘å½¢ç»“æž„ï¼Œç„¶åŽæ ¹æ®æ¯ä¸ªèŠ‚ç‚¹çš„ç›¸åº”çŠ¶æ€æ‰§è¡Œä¸åŒçš„æ“ä½œã€‚ ---------- 解决方案 ---------- 这里é‡åˆ°çš„é—®é¢˜åœ¨ç¼–ç¨‹é¢†åŸŸä¸æ˜¯å¾ˆæ™®é的,有时候会构建一个由大é‡ä¸åŒå¯¹è±¡ç»„æˆçš„æ•°æ®ç»“构。 å‡è®¾ä½ è¦å†™ä¸€ä¸ªè¡¨ç¤ºæ•°å¦è¡¨è¾¾å¼çš„程åºï¼Œé‚£ä¹ˆä½ å¯èƒ½éœ€è¦å®šä¹‰å¦‚下的类: .. code-block:: python 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 ç„¶åŽåˆ©ç”¨è¿™äº›ç±»æž„建嵌套数æ®ç»“构,如下所示: .. code-block:: python # Representation of 1 + 2 * (3 - 4) / 5 t1 = Sub(Number(3), Number(4)) t2 = Mul(Number(2), t1) t3 = Div(t2, Number(5)) t4 = Add(Number(1), t3) è¿™æ ·åšçš„问题是对于æ¯ä¸ªè¡¨è¾¾å¼ï¼Œæ¯æ¬¡éƒ½è¦é‡æ–°å®šä¹‰ä¸€éï¼Œæœ‰æ²¡æœ‰ä¸€ç§æ›´é€šç”¨çš„æ–¹å¼è®©å®ƒæ”¯æŒæ‰€æœ‰çš„æ•°å—å’Œæ“作符呢。 这里我们使用访问者模å¼å¯ä»¥è¾¾åˆ°è¿™æ ·çš„目的: .. code-block:: python 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__)) 为了使用这个类,å¯ä»¥å®šä¹‰ä¸€ä¸ªç±»ç»§æ‰¿å®ƒå¹¶ä¸”实现å„ç§ ``visit_Name()`` 方法,其ä¸Name是node类型。 ä¾‹å¦‚ï¼Œå¦‚æžœä½ æƒ³æ±‚è¡¨è¾¾å¼çš„值,å¯ä»¥è¿™æ ·å†™ï¼š .. code-block:: python 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 使用示例: .. code-block:: python >>> e = Evaluator() >>> e.visit(t4) 0.6 >>> 作为一个ä¸åŒçš„例å,下é¢å®šä¹‰ä¸€ä¸ªç±»åœ¨ä¸€ä¸ªæ ˆä¸Šé¢å°†ä¸€ä¸ªè¡¨è¾¾å¼è½¬æ¢æˆå¤šä¸ªæ“作åºåˆ—: .. code-block:: python class StackCode(NodeVisitor): def generate_code(self, node): self.instructions = [] self.visit(node) return self.instructions def visit_Number(self, node): self.instructions.append(('PUSH', node.value)) def binop(self, node, instruction): self.visit(node.left) self.visit(node.right) self.instructions.append((instruction,)) def visit_Add(self, node): self.binop(node, 'ADD') def visit_Sub(self, node): self.binop(node, 'SUB') def visit_Mul(self, node): self.binop(node, 'MUL') def visit_Div(self, node): self.binop(node, 'DIV') def unaryop(self, node, instruction): self.visit(node.operand) self.instructions.append((instruction,)) def visit_Negate(self, node): self.unaryop(node, 'NEG') 使用示例: .. code-block:: python >>> s = StackCode() >>> s.generate_code(t4) [('PUSH', 1), ('PUSH', 2), ('PUSH', 3), ('PUSH', 4), ('SUB',), ('MUL',), ('PUSH', 5), ('DIV',), ('ADD',)] >>> ---------- 讨论 ---------- åˆšå¼€å§‹çš„æ—¶å€™ä½ å¯èƒ½ä¼šå†™å¤§é‡çš„if/elseè¯å¥æ¥å®žçŽ°ï¼Œ 这里访问者模å¼çš„好处就是通过 ``getattr()`` æ¥èŽ·å–相应的方法,并利用递归æ¥é历所有的节点: .. code-block:: python def binop(self, node, instruction): self.visit(node.left) self.visit(node.right) self.instructions.append((instruction,)) è¿˜æœ‰ä¸€ç‚¹éœ€è¦æŒ‡å‡ºçš„æ˜¯ï¼Œè¿™ç§æŠ€æœ¯ä¹Ÿæ˜¯å®žçް其他è¯è¨€ä¸switch或caseè¯å¥çš„æ–¹å¼ã€‚ æ¯”å¦‚ï¼Œå¦‚æžœä½ æ£åœ¨å†™ä¸€ä¸ªHTTPæ¡†æž¶ï¼Œä½ å¯èƒ½ä¼šå†™è¿™æ ·ä¸€ä¸ªè¯·æ±‚分å‘的控制器: .. code-block:: python class HTTPHandler: def handle(self, request): methname = 'do_' + request.request_method getattr(self, methname)(request) def do_GET(self, request): pass def do_POST(self, request): pass def do_HEAD(self, request): pass 访问者模å¼ä¸€ä¸ªç¼ºç‚¹å°±æ˜¯å®ƒä¸¥é‡ä¾èµ–递归,如果数æ®ç»“构嵌套层次太深å¯èƒ½ä¼šæœ‰é—®é¢˜ï¼Œ 有时候会超过Python的递归深度é™åˆ¶(å‚考 ``sys.getrecursionlimit()`` )。 å¯ä»¥å‚ç…§8.22å°èŠ‚ï¼Œåˆ©ç”¨ç”Ÿæˆå™¨æˆ–è¿ä»£å™¨æ¥å®žçްéžé€’å½’é历算法。 在跟解æžå’Œç¼–译相关的编程ä¸ä½¿ç”¨è®¿é—®è€…æ¨¡å¼æ˜¯éžå¸¸å¸¸è§çš„。 Python本身的 ``ast`` 模å—值得关注下,å¯ä»¥åŽ»çœ‹çœ‹æºç 。 9.24å°èŠ‚æ¼”ç¤ºäº†ä¸€ä¸ªåˆ©ç”¨ ``ast`` æ¨¡å—æ¥å¤„ç†Pythonæºä»£ç 的例å。