# yield与递归

2017-01-13 10:57:30来源:csdn作者:neuldp人点击

yield中递归返回

1 递归中使用yield

def quick_sort(parameter_list):if len(parameter_list) == 0:
# print("error")
return
if len(parameter_list) == 1:
# print(parameter_list[0])
yield parameter_list[0]if parameter_list[0] < parameter_list[-1]:
pivot = parameter_list[0]
left = [i for i in parameter_list if i < pivot]
right = [i for i in parameter_list if i > pivot]
for item in quick_sort(left):
yield item
# quick_sort(left)#recursion in Generator are limited
yield pivot
# quick_sort(right)
for item in quick_sort(right):
yield item2 yield中递归返回

https://github.com/Earthson/RecGen

def fib(n):
if n <= 1:
yield n
else:
yield (yield RecTask(fib, n-1)) + (yield RecTask(fib, n-2))pfib = rec_gen(fib, lambda x: print(x))
for i in range(15):
pfib(i)实现思想

import sys
import types
from traceback import format_excdef rec_gen(func, callback=None, err_callback=None):
'''
callback accept arguments with output of func
err_callback is called after Exception occured, accept Exception instance as it's arguments
'''
def trans_func(*args, **kwargs):
def error_do(e):
print('@rec_func_error:', e, file=sys.stderr)
if err_callback is not None:
err_callback(e)
try:
g = func(*args, **kwargs)
except Exception as e:
error_do(e)
return
if not isinstance(g, types.GeneratorType):
#return if g is not generator
if callback is not None:
callback(g)
return
#ans = []
def go_through(it=None):
try:
em = g.send(it)
if not hasattr(em, 'dojob'):
#ans.append(em)
go_through(None)
else:
em.dojob(callback=go_through, err_callback=error_do)
except StopIteration as st:
if callback is not None:
callback(st.value)
return
except Exception as e:
g.close()
error_do(e)
return
go_through()
return trans_func
from functools import partial
def __init__(self, func, *args, **kwargs):
self.func = func
self.args = args
self.kwargs = kwargsdef dojob(self, callback=None, err_callback=None):
self.run(self.transform(partial(rec_gen, callback=callback, err_callback=err_callback)))def transform(self, f):
return f(self.func)def run(self, func=None):
if func is None:
func = self.func
return func(*self.args, **self.kwargs)
try_cnt = 0
def ierr(e, *args, **kwargs):
nonlocal try_cnt
if not hasattr(self, 'retry_limit') or try_cnt > self.retry_limit:
print('@error: overflow retry limit! task has complete failed', file=sys.stderr)
if err_callback is not None:
return err_callback(e, *args, **kwargs)
return
try_cnt += 1
print('@warning_retry: retry count: %s, %s' % (try_cnt, e), file=sys.stderr)
self.run(self.transform(partial(rec_gen, callback=callback, err_callback=ierr)))
self.run(self.transform(partial(rec_gen, callback=callback, err_callback=ierr)))
self.ans = [None for e in self.tasks]
self.flags = [False for e in self.tasks]
self.todo = callback
e.dojob(callback=self.acker(i), err_callback=err_callback)def acker(self, posi):
def ack(x):
if self.flags[posi] is False:
self.flags[posi] = True
self.ans[posi] = x
self.cnt -= 1
if self.cnt == 0:
if self.todo is not None:
self.todo(tuple(self.ans))
return ack
def __init__(self, sender, req, callback):
self.sender = sender
self.req = req
self.callback = callback
self.retry_limit = 10def transform(self, f):
return f(self.callback)def run(self, callback=None):
if callback is None:
callback = self.callback
self.sender(self.req, callback)
if __name__ == '__main__':
sys.setrecursionlimit(1000000000)
def fib(n):
if n <= 1:
return n
#return x + y
pfib = rec_gen(fib, lambda x: print(x))
pfib(25)