雖然不知道是誰最早發(fā)明yield來表達協(xié)程的秒裕,不過最近終于解鎖這一技能了俯萎,讓我感受到了上帝般的快感。
比方說我們要后序遍歷二叉樹,好啦我知道ACMer閉著眼睛都能默寫出來非遞歸版本架谎,讓我們看看遞歸版本先:
class Node(object):
def __init__(self, val, left, right):
self.val = val
self.left = left
self.right = right
def visit_post(node):
if node.left:
yield from visit_post(node.left)
if node.right:
yield from visit_post(node.right)
yield node.val
if __name__ == '__main__':
node = Node(-1, None, None)
for val in range(100):
node = Node(val, None, node)
print(list(visit_post(node)))
就是這么簡單,yield from
這么棒為什么你還在用Python2.x辟躏?
但是我們知道寫成遞歸動不動就爆棧了谷扣,非遞歸才是正義。不過不要怕捎琐,理解yield協(xié)程之后我們再也不必手動維護什么棧了会涎,裝逼變得異常簡單。
def visit_post(node):
if node.left:
yield node.left
if node.right:
yield node.right
yield node.val
def visit(node, visit_method):
stack = [visit_method(node)]
while stack:
last = stack[-1]
try:
yielded = next(last)
except StopIteration:
stack.pop()
else:
if isinstance(yielded, Node):
stack.append(visit_method(yielded))
elif isinstance(yielded, int):
yield yielded
if __name__ == '__main__':
node = Node(-1, None, None)
for val in range(100):
node = Node(val, None, node)
visit_generator = visit(node, visit_method=visit_post)
print(list(visit_generator))
excellent瑞凑!關鍵是很好理解對不對末秃,我以前一直認為我不把LeetCode刷7遍是不可能完成遞歸轉非遞歸的白板編程的,現(xiàn)在根本不是問題嘛籽御。
話說簡書的代碼高亮能不能專業(yè)點练慕,__builtins__
高亮很難?這根本就是態(tài)度問題技掏。
或者我們有遞歸搜索二叉樹最大值什么的:
def visit_maxvalue(node):
if node.left and node.right:
return max(node.val, visit_maxvalue(node.left), visit_maxvalue(node.right))
elif node.left:
return max(node.val, visit_maxvalue(node.left))
elif node.right:
return max(node.val, visit_maxvalue(node.right))
else:
return node.val
非遞歸版本也是非常平易近人:
def visit_max_maxvalue(node):
if node.left and node.right:
yield max(node.val, (yield node.left), (yield node.right))
elif node.left:
yield max(node.val, (yield node.left))
elif node.right:
yield max(node.val, (yield node.right))
else:
yield node.val
def visit(node, visit_method):
stack = [visit_method(node)]
current = None
while stack:
last = stack[-1]
try:
yielded = last.send(current)
except StopIteration:
stack.pop()
else:
if isinstance(yielded, Node):
stack.append(visit_method(yielded))
current = None
elif isinstance(yielded, int):
current = yielded
return current
逼格飽滿有木有铃将!
BTW,著名的Tornado就是用yield
協(xié)程來實現(xiàn)異步零截,大愛麸塞!