Try to fix transient refleaks in test_asynchat.
[python.git] / Demo / classes / Range.py
blob3f1daaead6925e0b8015da71162cb49923fd7232
1 """Example of a generator: re-implement the built-in range function
2 without actually constructing the list of values.
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__ .
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")
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
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)
39 Done using the old way (pre-iterators; __len__ and __getitem__) to have an
40 object be used by a 'for' loop.
42 """
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)
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)
54 def __len__(self):
55 """implement len(x)"""
56 return self.len
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'
66 def test():
67 import time, __builtin__
68 #Just a quick sanity check
69 correct_result = __builtin__.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 __builtin__.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)'
92 if __name__ == '__main__':
93 test()