Welcome, guest | Sign In | My Account | Store | Cart

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.

Python, 61 lines
 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.