双向生成模型

3
如何在Python中创建一个2-shot生成器?
我的尝试(不起作用):
>>> def g():
...     try:
...         yield 1
...         raise StopIteration('Shot 1 exhausted')
...     finally:
...         yield 2
...         # 'Shot 2 exhausted'
...         
>>> x = g()
>>> list(x), list(x)
([1, 2], [])
# expected output ([1], [2])
1个回答

3

迭代器协议明确禁止这样做:

该协议的意图是一旦迭代器的next()方法引发StopIteration,它将在后续调用中继续这样做。不遵守此属性的实现被视为有缺陷。

因此,生成器语法没有提供制作2-shot迭代器的方法。

如果您真的想这样做,就不能使用生成器:

class BrokenIterator(object):
    def __init__(self):
        self.callcount = 0
    def __iter__(self):
        return self
    def next(self):
        self.callcount += 1
        if self.callcount == 1:
            return 1
        elif self.callcount == 3:
            return 2
        else:
            raise StopIteration

1
在他的代码中,没有任何东西阻止了在后续对next()函数的调用中引发StopIteration异常... - metatoaster
使用这种方法会得到 TypeError: iter() returned non-iterator of type 'BrokenIterator' 的错误。不过,我想尝试使用 yield 来解决问题。 - wim
@wim:对我来说可以。你使用的是Python 3吗?如果是,那么next方法将需要更改为__next__。如果你想尝试使用yield来完成它,可以试试,但你可能需要作弊。例如,创建一个对象,其__iter__方法是修改对象状态的生成器 - 但是该对象不是迭代器,只是一个2-shot可迭代对象。 - user2357112
是的,Python 3!我知道如何使用自定义类来实现,但当我尝试使用生成器函数时,使用yield并通过使用可变默认参数来维护状态时,它没有起作用 :) - wim
@metatoaster:他的使用情况特别要求他的生成器先产生1,然后引发StopIteration异常,接着产生2,再次引发StopIteration异常。 - user2357112
@user2357112,我看到了您提供的逻辑,但是由于缺乏对“2-shot生成器”的解释,我认为它是一个返回两个值的生成器。 - metatoaster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接