| # Example of a generator: re-implement the built-in range function |
| # without actually constructing the list of values. (It turns out |
| # that the built-in function is about 20 times faster -- that's why |
| # it's built-in. :-) |
| |
| |
| # Wrapper function to emulate the complicated range() arguments |
| |
| def range(*a): |
| if len(a) == 1: |
| start, stop, step = 0, a[0], 1 |
| elif len(a) == 2: |
| start, stop = a |
| step = 1 |
| elif len(a) == 3: |
| start, stop, step = a |
| else: |
| raise TypeError, 'range() needs 1-3 arguments' |
| return Range(start, stop, step) |
| |
| |
| # Class implementing a range object. |
| # To the user the instances feel like immutable sequences |
| # (and you can't concatenate or slice them) |
| |
| class Range: |
| |
| # initialization -- should be called only by range() above |
| def __init__(self, start, stop, step): |
| if step == 0: |
| raise ValueError, 'range() called with zero step' |
| self.start = start |
| self.stop = stop |
| self.step = step |
| self.len = max(0, int((self.stop - self.start) / self.step)) |
| |
| # implement `x` and is also used by print x |
| def __repr__(self): |
| return 'range' + `self.start, self.stop, self.step` |
| |
| # implement len(x) |
| def __len__(self): |
| return self.len |
| |
| # implement x[i] |
| def __getitem__(self, i): |
| if 0 <= i < self.len: |
| return self.start + self.step * i |
| else: |
| raise IndexError, 'range[i] index out of range' |
| |
| |
| # Small test program |
| |
| def test(): |
| import time, __builtin__ |
| print range(10), range(-10, 10), range(0, 10, 2) |
| for i in range(100, -100, -10): print i, |
| print |
| t1 = time.time() |
| for i in range(1000): |
| pass |
| t2 = time.time() |
| for i in __builtin__.range(1000): |
| pass |
| t3 = time.time() |
| print t2-t1, 'sec (class)' |
| print t3-t2, 'sec (built-in)' |
| |
| |
| test() |