Подтвердить что ты не робот

Выход python и остановка в одном цикле?

У меня есть генератор, где я хотел бы добавить начальное и конечное значение к фактическому содержимому, это примерно так:

# 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. любые идеи?

Приветствия,

4b9b3361

Ответ 1

Вы, кажется, слишком сильно себя чувствуете:

>>> 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 каждое значение, которое вы хотите вернуть из генератора по очереди, затем верните функцию.

Ответ 2

Здесь код, в котором использование 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

результат

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()