[英]Why can't my except block catch a StopIteration exception?
我想用這個程序做的是我希望它通過使用遞歸一遍又一遍地返回“是”和“否”。 請幫忙? 難道我做錯了什么?
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 即使我認為我在錯誤處理中發現了它?
在yield
調用中不會引發StopIteration
異常,因此您不會使用該 try/except 設置來捕獲它。
通過在您的 function 中有一個yield
語句,您已經將它變成了一個生成器(您似乎理解)。 每次評估生成器時,它都會在上次完成的產量處重新進入,並繼續進行直到下一次產量或 function 完成。 因此,在您的第三次next()
中,執行將在yield
處恢復,返回for
循環,看到它已完成,然后繼續執行,在這種情況下,這只是 function 的結束。 function 將返回,因此生成器將提高其 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。
循環內的yield x
永遠不會raise StopIteration
,因此您無法捕獲它。 Python for
循環是使用StopIteration
實現的,是的,但是在您處理它之前就捕獲了那里引發的實例。
使您想到的工作的方法是……讓循環運行,然后產生元素的 rest。 遞歸:
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
呢? 通過在迭代器實現中顯式提升它(盡管最明顯的方法已經為您完成了),或者在您使用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')
這是一個簡單的遞歸解決方案:
def yes_or_no():
yield from ('yes', 'no')
yield from yes_or_no()
編輯:
itertools
模塊具有 function cycle
,該循環接收一個迭代器並返回一個循環通過其輸入的生成器。
import itertools
def yes_or_no():
yield from itertools.cycle(("yes", "no"))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.