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

This function allow to use a slice like protocol on iterators.

Python, 54 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
import sys
def iterslice(sequence, start=None, stop=None, step=1):
    if step == 0:
        raise ValueError, "Attempt to use 0 as step value"
    if stop is None:
        stop = sys.maxint*cmp(step,0)
    elif stop<0: 
        try:
            stop = max(len(sequence)+stop,0)
        except TypeError:
            raise TypeError, "Negative slice index on unsized sequence"
    if start is None:
        if step>0: 
            start = 0
        else:
            try:
                start = len(sequence)-1
            except TypeError:
                raise TypeError, ("Unable to start from the end of an "
                                  "unsized sequence")
    elif start<0: 
        try:
            start = max(len(sequence)+start,0)
        except TypeError:
            raise TypeError, "Negative slice index on unsized sequence"
    try:
        for i in xrange(start, stop, step):
                yield sequence[i]
    except IndexError:
        return
    except TypeError:
        if step<0:
            raise TypeError, ("Attempt to use negative step on an "
                              "unindexable sequence")
        #check if the sequence support iterator protocol
        itr = iter(sequence)
        try:
            for i in xrange(start):
                itr.next()
            while start<stop:
                yield itr.next()
                for i in xrange(step-1):
                    itr.next()
                start+=step
        except StopIteration:
            return
        
#
# sample
#      
X = [chr(x) for x in range(100)]
print list(iterslice(X,10,20))
print list(iterslice(iter(X),10,20))
print X[10:20]

This generator allow you to use the same call conventions than slices when you want to use iterator as output, or when the sequence is not sliceable. The iterslice function can be used on any iterable sequence with the following constraints: - if start or stop params are negatives, the sequence must support the len function. - if start is not specified and step is negative, the sequence must support the len function. - if step is negative the sequence must support indexing.

Warning: The iterslice function protocol differ from the standard slice function in one point: iterslice(X,3) is equivalent to iter(X[3:]) where in python 2.3, X[slice(3)] would be equivalent to X[:3] This can be confusing, but keeping the notation coherent with slice function would make impossible to get the equivalent of iter(X[3:]) when X is an iterator.