~ubuntu-branches/ubuntu/maverick/python3.1/maverick

« back to all changes in this revision

Viewing changes to Demo/classes/Range.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2009-03-23 00:01:27 UTC
  • Revision ID: james.westby@ubuntu.com-20090323000127-5fstfxju4ufrhthq
Tags: upstream-3.1~a1+20090322
ImportĀ upstreamĀ versionĀ 3.1~a1+20090322

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""Example of a generator: re-implement the built-in range function
 
2
without actually constructing the list of values.
 
3
 
 
4
OldStyleRange is coded in the way required to work in a 'for' loop before
 
5
iterators were introduced into the language; using __getitem__ and __len__ .
 
6
 
 
7
"""
 
8
def handleargs(arglist):
 
9
    """Take list of arguments and extract/create proper start, stop, and step
 
10
    values and return in a tuple"""
 
11
    try:
 
12
        if len(arglist) == 1:
 
13
            return 0, int(arglist[0]), 1
 
14
        elif len(arglist) == 2:
 
15
            return int(arglist[0]), int(arglist[1]), 1
 
16
        elif len(arglist) == 3:
 
17
            if arglist[2] == 0:
 
18
                raise ValueError("step argument must not be zero")
 
19
            return tuple(int(x) for x in arglist)
 
20
        else:
 
21
            raise TypeError("range() accepts 1-3 arguments, given", len(arglist))
 
22
    except TypeError:
 
23
        raise TypeError("range() arguments must be numbers or strings "
 
24
        "representing numbers")
 
25
 
 
26
def genrange(*a):
 
27
    """Function to implement 'range' as a generator"""
 
28
    start, stop, step = handleargs(a)
 
29
    value = start
 
30
    while value < stop:
 
31
        yield value
 
32
        value += step
 
33
 
 
34
class oldrange:
 
35
    """Class implementing a range object.
 
36
    To the user the instances feel like immutable sequences
 
37
    (and you can't concatenate or slice them)
 
38
 
 
39
    Done using the old way (pre-iterators; __len__ and __getitem__) to have an
 
40
    object be used by a 'for' loop.
 
41
 
 
42
    """
 
43
 
 
44
    def __init__(self, *a):
 
45
        """ Initialize start, stop, and step values along with calculating the
 
46
        nubmer of values (what __len__ will return) in the range"""
 
47
        self.start, self.stop, self.step = handleargs(a)
 
48
        self.len = max(0, (self.stop - self.start) // self.step)
 
49
 
 
50
    def __repr__(self):
 
51
        """implement repr(x) which is also used by print"""
 
52
        return 'range(%r, %r, %r)' % (self.start, self.stop, self.step)
 
53
 
 
54
    def __len__(self):
 
55
        """implement len(x)"""
 
56
        return self.len
 
57
 
 
58
    def __getitem__(self, i):
 
59
        """implement x[i]"""
 
60
        if 0 <= i <= self.len:
 
61
            return self.start + self.step * i
 
62
        else:
 
63
            raise IndexError('range[i] index out of range')
 
64
 
 
65
 
 
66
def test():
 
67
    import time, builtins
 
68
    #Just a quick sanity check
 
69
    correct_result = builtins.range(5, 100, 3)
 
70
    oldrange_result = list(oldrange(5, 100, 3))
 
71
    genrange_result = list(genrange(5, 100, 3))
 
72
    if genrange_result != correct_result or oldrange_result != correct_result:
 
73
        raise Exception("error in implementation:\ncorrect   = %s"
 
74
                         "\nold-style = %s\ngenerator = %s" %
 
75
                         (correct_result, oldrange_result, genrange_result))
 
76
    print("Timings for range(1000):")
 
77
    t1 = time.time()
 
78
    for i in oldrange(1000):
 
79
        pass
 
80
    t2 = time.time()
 
81
    for i in genrange(1000):
 
82
        pass
 
83
    t3 = time.time()
 
84
    for i in builtins.range(1000):
 
85
        pass
 
86
    t4 = time.time()
 
87
    print(t2-t1, 'sec (old-style class)')
 
88
    print(t3-t2, 'sec (generator)')
 
89
    print(t4-t3, 'sec (built-in)')
 
90
 
 
91
 
 
92
if __name__ == '__main__':
 
93
    test()