Variant of iter(func, sentinel) that looks for an exception rather than for a sentinel value. Good for making iterators from of APIs that advance over a data and return an exception when they are done.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | def iter_except(func, exception, start=None):
'Yield a function repeatedly until it raises an exception'
try:
if start is not None:
yield start()
while 1:
yield func()
except exception:
pass
### Examples ####################################################
if __name__ == '__main__':
# Example using BSDDB's last() and next() methods
import bsddb
db = bsddb.btopen('/tmp/spam.db', 'c')
for i in range(10):
db['%d'%i] = '%d'% (i*i)
for k, v in iter_except(db.next, bsddb.error, start=db.first):
print k, v
# Example of fetching tasks from a priority queue
from random import random
from heapq import heappush, heappop
from functools import partial
pq = []
for i in range(10):
heappush(pq, (random(), 'task %d' % i))
for priority, task in iter_except(partial(heappop, pq), IndexError):
print priority, task
# Example of atomic, destructive reads from a dictionary
d = dict(enumerate('abcdefghi'))
for k, v in iter_except(d.popitem, KeyError):
print k, v
# Example of atomic, destructive reads from a deque
import collections
d = collections.deque('abcdefghi')
for v in iter_except(d.popleft, IndexError):
print v
# Example of iterating over a producer Queue:
import Queue
q = Queue.Queue()
for i in range(10):
q.put('*' * i)
for v in iter_except(q.get_nowait, Queue.Empty):
print v
# Example of iterating destructively over a set
s = set('abracadabra')
for elem in iter_except(s.pop, KeyError):
print elem
|
Python and its third-party modules are commonly filled with APIs that retrieve successive pieces of data and raise exceptions when the data is exhausted.
This simple tool adapts those APIs to support the iterator protocol, making them much easier to use. An iterator can be consumed directly in a for-loop. Alternatively, it can be fed directly into other functions like set(), sorted(), sum(), min(), max(), list(), enumerate(), or any of the many functions in the itertools module.