Python 为什么可以';我的块是否捕获StopIteration异常?

Python 为什么可以';我的块是否捕获StopIteration异常?,python,Python,我想用这个程序做的是,我想让它通过递归一次又一次地返回“是”和“否”。请帮忙!我做错什么了吗 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)) 当它到达第三次打印时,

我想用这个程序做的是,我想让它通过递归一次又一次地返回“是”和“否”。请帮忙!我做错什么了吗

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设置捕获它

通过在函数中使用
yield
语句,您已经将其转换为生成器(您似乎理解)。每次评估生成器时,它将在上次完成的产量处重新输入,并继续执行,直到下一个产量或函数完成。因此,在第三次
next()
,执行将在
产生时恢复,返回
for
循环,查看它是否完成,然后继续执行,在本例中,这只是函数的结束。函数将返回,因此生成器将提高其StopIteration

我不建议在这个任务中使用递归;只需在(“是”、“否”)循环周围使用一个外部无限循环(或者更好的是,使用itertools中的某些内容)

如果您真的想使用递归,那么您可能想试试

def yes_或_no():
对于x英寸(“是”、“否”):
产量x
是或否的收益率()

我认为
yield from
位需要Python>=3.3。

yield
调用中没有引发
StopIteration
异常,因此您将无法通过try/except设置捕获它

通过在函数中使用
yield
语句,您已将其转换为生成器(您似乎理解)。每次对生成器求值时,它都将在上次完成的yield处重新输入,并一直执行到下一个yield或函数完成。因此,在第三个
next()
,执行将在
yield
处恢复,返回
for
循环,查看它是否完成,然后继续执行,在这种情况下,这只是函数的结束。函数将返回,因此生成器将提升其StopIteration

我不建议您在这个任务中使用递归;只需在(“yes”,“no”)循环周围使用一个外部无限循环(或者更好的是,使用itertools中的某些东西)

如果您真的想使用递归,那么您可能想试试

def yes_或_no():
对于x英寸(“是”、“否”):
产量x
是或否的收益率()

我认为,
yield from
位需要Python>=3.3。循环中的
yield x
永远不会
引发StopIteration
,因此您无法捕获它。Python
for
循环是使用
StopIteration
实现的,这是真的,但是在您处理它之前就捕获了在那里引发的实例

让你的想法发挥作用的方法就是。。。让循环运行,然后生成其余的元素。递归地:

def yes_or_no():
    for x in ("yes","no"):
        yield x
    yield from yes_or_no()
另一方面:
yield from
是继续生成递归调用生成的元素所需要的。生成器的
返回值
无助于生成更多元素。具有讽刺意味的是,事实上,它设置了一个异常,该异常导致生成器在元素不足的情况下运行:

>>> 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
或者使用
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')

yield x
循环内部永远不会
引发StopIteration
,因此您无法捕获它。Python
for
循环是使用
StopIteration
实现的,这是真的,但是在您处理它之前就捕获了在那里引发的实例

让你的想法发挥作用的方法就是。。。让循环运行,然后生成其余的元素。递归地:

def yes_or_no():
    for x in ("yes","no"):
        yield x
    yield from yes_or_no()
另一方面:
yield from
是继续生成递归调用生成的元素所需要的。生成器的
返回值
无助于生成更多元素。具有讽刺意味的是,事实上,它设置了一个异常,该异常导致生成器在元素不足的情况下运行:

>>> 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
或者使用
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
模块具有接收迭代器并返回循环输入的生成器的功能

import itertools
def yes_or_no():
    yield from itertools.cycle(("yes", "no"))

下面是一个简单的递归解决方案:

def yes_or_no():
    yield from ('yes', 'no')
    yield from yes_or_no()
编辑:

itertools
模块具有接收迭代器并返回循环输入的生成器的功能

import itertools
def yes_or_no():
    yield from itertools.cycle(("yes", "no"))

这将不起作用,因为for循环只运行两次。您是否正在尝试创建一个循环函数,如?当两次迭代后
for
循环结束时,该函数将返回(在退出时不会引发
StopIteration
异常)。这将不起作用,因为for循环只会运行两次。您是否正在尝试创建一个循环函数,如?当两次迭代后
for
循环结束时,函数将返回(在退出时不会引发
StopIteration
异常)。您对版本要求的看法是正确的:您对版本要求的看法是正确的: