我不认为这是一个常见的用例,将其视为原始生成器:
def original_gen():
for x in range(10):
should_break = yield x
if should_break:
break
如果should_break 的值总是基于x 的某个函数调用计算得出,那么为什么不直接编写生成器:
def processing_gen(check_f):
for x in range(10):
yield x
should_break = check_f(x)
if should_break:
break
但是我通常认为处理生成的值的代码是写在循环中的(否则有循环的意义何在?)
看起来你真正想要做的是创建一个生成器,其中调用__next__ 方法实际上意味着send(process(LAST_VALUE)) 可以用一个类来实现:
class Followup_generator(): #feel free to use a better name
def __init__(self,generator,following_function):
self.gen = generator
self.process_f = following_function
def __iter__(self):
return self
def __next__(self):
if hasattr(self,"last_value"):
return self.send(self.process_f(self.last_value))
else:
self.last_value = next(self.gen)
return self.last_value
def send(self,arg):
self.last_value = self.gen.send(arg)
return self.last_value
def __getattr__(self,attr):
"forward other lookups to the generator (.throw etc.)"
return getattr(self.gen, attr)
# call signature is the exact same as @tobias_k's checking_generator
traversal = Followup_generator(bfs(g, start_node), process)
for n in traversal:
print(n)
n = traversal.send(DATA) #you'd be able to send extra values to it
但是,这仍然没有被认为是经常使用的,我可以使用 while 循环,尽管我会将 .send 调用放在顶部:
traversal = bfs(g, start_node)
send_value = None
while True:
n = traversal.send(send_value)
#code for loop, ending in calculating the next send_value
send_value = process(n)
您可以将其包装在 try: ... except StopIteration:pass 中,尽管我发现使用上下文管理器更好地表达只是等待错误引发:
class Catch:
def __init__(self,exc_type):
if issubclass(exc_type,BaseException):
self.catch_type = exc_type
else:
raise TypeError("can only catch Exceptions")
def __enter__(self):
return self
def __exit__(self,exc_type,err, tb):
if issubclass(exc_type, self.catch_type):
self.err = err
return True
with Catch(StopIteration):
traversal = bfs(g, start_node)
send_value = None
while True:
n = traversal.send(send_value)
#code for loop, ending in calculating the next send_value
send_value = process(n)