我要对该程序执行的操作是希望它通过使用递归一次又一次地返回“是”和“否”。请帮忙!我在做错什么吗?
def yes_or_no():
for x in ("yes","no"):
try:
yield x
except (StopIteration):
return yes_or_no()
gen = yes_or_no()
print(next(gen))
print(next(gen))
print(next(gen))
到达第三张打印纸后,即使我以为我在错误处理中发现了它,它也会显示StopIteration?
答案 0 :(得分:1)
StopIteration
调用中不会引发yield
异常,因此您不会通过try / except设置来捕获它。
通过在函数中使用yield
语句,您已将其转换为生成器(您似乎可以理解)。每次评估生成器时,它将以上次完成的成品率重新输入,并继续进行直到下一个成品率或函数完成为止。因此,在您的第三个next()
上,执行将在yield
处继续,回到for
循环,看看它完成了,然后继续进行,这只是结束了。在这种情况下的功能。该函数将返回,因此生成器将提高其StopIteration。
我不建议您对这个任务使用递归;只需在(“ yes,” no“)循环周围使用外部无限循环(或者更好的是,来自itertools的东西)。
如果您真的想使用递归,那么您可能想尝试
def yes_or_no():
for x in ("yes", "no"):
yield x
yield from yes_or_no()
我认为yield from
位需要Python> = 3.3。
答案 1 :(得分:1)
yield x
永远不会raise StopIteration
,因此您无法捕获它。 Python for
循环是使用StopIteration
实现的,确实如此,但是在那里引发的实例在被您处理之前就被捕获了。
使您的想法起作用的方法是...让循环运行,然后产生其余元素。递归:
def yes_or_no():
for x in ("yes","no"):
yield x
yield from yes_or_no()
顺便说一句:yield from
是您需要的,以便继续产生递归调用产生的元素。生成器的return
值不能帮助您产生更多元素。具有讽刺意味的是,实际上,它设置了导致生成器元素不足的结果的异常:
>>> def example():
... yield 1
... return 2
...
>>> x = example()
>>> next(x)
1
>>> next(x)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration: 2
(当然,您的整个目标是让yes_or_no()
不是用尽所有元素,所以。)
无论如何,为此使用递归是一个坏主意,因为您人为地限制了递归的工作时间(直到堆栈帧用完)。只是迭代:
def yes_or_no():
while True:
yield 'yes'
yield 'no'
或使用itertools
:
>>> import itertools
>>> x = itertools.cycle(('yes', 'no'))
>>> next(x)
'yes'
>>> next(x)
'no'
>>> next(x)
'yes'
>>> next(x)
'no'
那么如何您如何在用户代码中充分利用StopIteration
?通过在 iterator 实现中显式提高它(尽管最明显的方法已经为您完成),或者通过在手动推进迭代器时捕获它使用next
。例子:
class SingletonIterator:
"""Proxy iterator to allow 'iteration' over a fictitious sequence
holding a single element, the `value`."""
def __init__(self, value):
self._value = value
self._yielded = False
def __iter__(self):
return self
def __next__(self):
if self._yielded:
raise StopIteration
self._yielded = True
return self._value
def first(predicate, sequence):
"""The first element `e` of `sequence` satisfying `predicate(e)`.
Raises ValueError for an empty sequence."""
try:
return next(e for e in sequence if predicate(e))
except StopIteration:
raise ValueError('empty sequence')
答案 2 :(得分:0)
这是一个简单的递归解决方案:
def yes_or_no():
yield from ('yes', 'no')
yield from yes_or_no()
编辑:
itertools
模块具有函数cycle
,该函数接受迭代器并返回生成器,该生成器循环其输入。
import itertools
def yes_or_no():
yield from itertools.cycle(("yes", "no"))