python yield and stopiteration in one loop?
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 somethin开发者_运维知识库g 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,
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.
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()
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
精彩评论