python yield 和 stopiteration 在一个循环中?

发布于 2024-11-26 05:56:49 字数 634 浏览 1 评论 0原文

我有一个生成器,我想在其中添加初始值和最终值到实际内容中,它是这样的:

# any generic queue where i would like to get something from
q = Queue()

def gen( header='something', footer='anything' ):
    # initial value header
    yield header

    for c in count():
        # get from the queue
        i = q.get()
        # if we don't have any more data from the queue, spit out the footer and stop
        if i == None:
            yield footer
            raise StopIteration
        else:
            yield i

当然,上面的代码不起作用 - 我的问题是我希望这样当没有剩下任何东西时在队列中,我希望生成器吐出 footer 并引发 StopIterator。有什么想法吗?

干杯,

i have a generator where i would like to add an initial and final value to the actual content, it's something like this:

# any generic queue where i would like to get something from
q = Queue()

def gen( header='something', footer='anything' ):
    # initial value header
    yield header

    for c in count():
        # get from the queue
        i = q.get()
        # if we don't have any more data from the queue, spit out the footer and stop
        if i == None:
            yield footer
            raise StopIteration
        else:
            yield i

Of course, the above code doesn't work - my problem is that i would like it such that when there's nothing left in the queue, i want the generator to spit out the footer AND raise the StopIterator. any ideas?

Cheers,

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

天生の放荡 2024-12-03 05:56:49

您似乎使这一点变得过于复杂:

>>> q = [1, 2, 3, 4]
>>> def gen(header='something', footer='anything'):
        yield header
        for thing in q:
            yield thing
        yield footer


>>> for tmp in gen():
        print(tmp)


something
1
2
3
4
anything

当生成器停止产生时,将自动引发 StopIteration 。它是生成器工作协议的一部分。除非您正在做一些非常复杂的事情,否则您根本不需要(也不应该)处理 StopIteration。只需yield依次从生成器返回的每个值,然后让函数返回即可。

You seem to be overcomplicating this quite a bit:

>>> q = [1, 2, 3, 4]
>>> def gen(header='something', footer='anything'):
        yield header
        for thing in q:
            yield thing
        yield footer


>>> for tmp in gen():
        print(tmp)


something
1
2
3
4
anything

StopIteration will automatically be raised when a generator stops yielding. It's part of the protocol of how generators work. Unless you're doing something very complex, you don't need to (and shouldn't) deal with StopIteration at all. Just yield each value you want to return from the generator in turn, then let the function return.

长梦不多时 2024-12-03 05:56:49

这是一个不需要使用 StopIteration 的代码,一个中断就足够了:

li = [12,51,98,4,36,99,33,1,125,78,9,369,48,47,214,4]

def gen( cont, header='something', footer='anything' ):
    yield header
    for x in cont:
        if x<100:
            yield x
        else:
            yield footer
            break

for y in gen(li):
    print '1 or 2 digits only:',y

result

1 or 2 digits only: something
1 or 2 digits only: 12
1 or 2 digits only: 51
1 or 2 digits only: 98
1 or 2 digits only: 4
1 or 2 digits only: 36
1 or 2 digits only: 99
1 or 2 digits only: 33
1 or 2 digits only: 1
1 or 2 digits only: anything

现在,这是一个中等复杂的代码,在我看来,我们不能不使用 StopIteration。您对此感兴趣吗?

import Queue
q = Queue.Queue()

li = [12,51,98,4,36,99,33,1,125,78,9,369,48,47,214,4]

def gen( cont, header='something', footer='anything' ):
    def qput(ili = [0]):
        eli = li[ili[0]]
        q.put(eli)
        ili[0] = ili[0] + 1
        return eli

    qput()
    qput()
    qput()
    qput()
    qput()
    yield header

    while True:
        try:
            print '\nq.qsize() first is %s' % q.qsize()

            el = q.get(None)

            if el>9:
                print 'el==',el
                yield 1000+el
                qput()
            else:
                print 'el==%s   el//3==%s' % (el,el//3)
                print 'there are %s items in q and q is emptied %s times :' % (q.qsize(),el//3)
                for emp in xrange(el//3):
                    print '%s is removed from q' % q.get(None)
                    if q.qsize()==0 and emp<el//3:
                        print 'ah !! q is now completely empty, no more emptying is possible !'

            print 'q.qsize() second is %s' % q.qsize()

        except Queue.Empty:
            yield footer
            raise StopIteration


print 'li == %s\n' % li
for i,nb in enumerate(gen(li)):
    print ' * obtained from enumerate(gen(li)) : %s - %s' % (i,nb)

结果

li == [12, 51, 98, 4, 36, 99, 33, 1, 125, 78, 9, 369, 48, 47, 214, 4]

 * obtained from enumerate(gen(li)) : 0 - something

q.qsize() first is 5
el== 12
 * obtained from enumerate(gen(li)) : 1 - 1012
q.qsize() second is 5

q.qsize() first is 5
el== 51
 * obtained from enumerate(gen(li)) : 2 - 1051
q.qsize() second is 5

q.qsize() first is 5
el== 98
 * obtained from enumerate(gen(li)) : 3 - 1098
q.qsize() second is 5

q.qsize() first is 5
el==4   el//3==1
there are 4 items in q and q is emptied 1 times :
36 is removed from q
q.qsize() second is 3

q.qsize() first is 3
el== 99
 * obtained from enumerate(gen(li)) : 4 - 1099
q.qsize() second is 3

q.qsize() first is 3
el== 33
 * obtained from enumerate(gen(li)) : 5 - 1033
q.qsize() second is 3

q.qsize() first is 3
el==1   el//3==0
there are 2 items in q and q is emptied 0 times :
q.qsize() second is 2

q.qsize() first is 2
el== 125
 * obtained from enumerate(gen(li)) : 6 - 1125
q.qsize() second is 2

q.qsize() first is 2
el== 78
 * obtained from enumerate(gen(li)) : 7 - 1078
q.qsize() second is 2

q.qsize() first is 2
el==9   el//3==3
there are 1 items in q and q is emptied 3 times :
369 is removed from q
ah !! q is now completely empty, no more emptying is possible !
 * obtained from enumerate(gen(li)) : 8 - anything

请注意,该程序仅使用 q.get(None) 正确运行,而不是 q.get()

Here's a code in which use of StopIteration isn't required, a break is enough:

li = [12,51,98,4,36,99,33,1,125,78,9,369,48,47,214,4]

def gen( cont, header='something', footer='anything' ):
    yield header
    for x in cont:
        if x<100:
            yield x
        else:
            yield footer
            break

for y in gen(li):
    print '1 or 2 digits only:',y

result

1 or 2 digits only: something
1 or 2 digits only: 12
1 or 2 digits only: 51
1 or 2 digits only: 98
1 or 2 digits only: 4
1 or 2 digits only: 36
1 or 2 digits only: 99
1 or 2 digits only: 33
1 or 2 digits only: 1
1 or 2 digits only: anything

Now, here's a moderately complex code in which it seems to me that we can't do without use of StopIteration. Does this interest you ?

import Queue
q = Queue.Queue()

li = [12,51,98,4,36,99,33,1,125,78,9,369,48,47,214,4]

def gen( cont, header='something', footer='anything' ):
    def qput(ili = [0]):
        eli = li[ili[0]]
        q.put(eli)
        ili[0] = ili[0] + 1
        return eli

    qput()
    qput()
    qput()
    qput()
    qput()
    yield header

    while True:
        try:
            print '\nq.qsize() first is %s' % q.qsize()

            el = q.get(None)

            if el>9:
                print 'el==',el
                yield 1000+el
                qput()
            else:
                print 'el==%s   el//3==%s' % (el,el//3)
                print 'there are %s items in q and q is emptied %s times :' % (q.qsize(),el//3)
                for emp in xrange(el//3):
                    print '%s is removed from q' % q.get(None)
                    if q.qsize()==0 and emp<el//3:
                        print 'ah !! q is now completely empty, no more emptying is possible !'

            print 'q.qsize() second is %s' % q.qsize()

        except Queue.Empty:
            yield footer
            raise StopIteration


print 'li == %s\n' % li
for i,nb in enumerate(gen(li)):
    print ' * obtained from enumerate(gen(li)) : %s - %s' % (i,nb)

result

li == [12, 51, 98, 4, 36, 99, 33, 1, 125, 78, 9, 369, 48, 47, 214, 4]

 * obtained from enumerate(gen(li)) : 0 - something

q.qsize() first is 5
el== 12
 * obtained from enumerate(gen(li)) : 1 - 1012
q.qsize() second is 5

q.qsize() first is 5
el== 51
 * obtained from enumerate(gen(li)) : 2 - 1051
q.qsize() second is 5

q.qsize() first is 5
el== 98
 * obtained from enumerate(gen(li)) : 3 - 1098
q.qsize() second is 5

q.qsize() first is 5
el==4   el//3==1
there are 4 items in q and q is emptied 1 times :
36 is removed from q
q.qsize() second is 3

q.qsize() first is 3
el== 99
 * obtained from enumerate(gen(li)) : 4 - 1099
q.qsize() second is 3

q.qsize() first is 3
el== 33
 * obtained from enumerate(gen(li)) : 5 - 1033
q.qsize() second is 3

q.qsize() first is 3
el==1   el//3==0
there are 2 items in q and q is emptied 0 times :
q.qsize() second is 2

q.qsize() first is 2
el== 125
 * obtained from enumerate(gen(li)) : 6 - 1125
q.qsize() second is 2

q.qsize() first is 2
el== 78
 * obtained from enumerate(gen(li)) : 7 - 1078
q.qsize() second is 2

q.qsize() first is 2
el==9   el//3==3
there are 1 items in q and q is emptied 3 times :
369 is removed from q
ah !! q is now completely empty, no more emptying is possible !
 * obtained from enumerate(gen(li)) : 8 - anything

Note that this program runs correctly only with q.get(None) , not q.get()

寄与心 2024-12-03 05:56:49

我来自未来。我推荐 yield from:

def gen(q, header="header", footer="footer"):
    yield header
    yield from q
    yield footer

输出:

>>> g = gen([1, 2, 3, 4])
>>> print(*g, sep="\n")
header
1
2
3
4
footer

I come from the future. I recommend yield from:

def gen(q, header="header", footer="footer"):
    yield header
    yield from q
    yield footer

Output:

>>> g = gen([1, 2, 3, 4])
>>> print(*g, sep="\n")
header
1
2
3
4
footer
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文