The range() function in Python generates a sequence of numbers. It’s commonly used for looping a specific number of times in for loops. While the range() function appears straightforward, its implementation is a bit more complex.
Here’s a detailed look at how the range() function is implemented and how it works.
Source Code of range() Function
The range() function is implemented in C in the CPython interpreter for performance reasons. Below is a simplified Python version that mimics the functionality of the range() function.
Simplified Python Implementation of range()
class Range:
def __init__(self, start, stop=None, step=1):
if stop is None:
self.start = 0
self.stop = start
else:
self.start = start
self.stop = stop
self.step = step
if step == 0:
raise ValueError("range() arg 3 must not be zero")
if not isinstance(start, int) or not isinstance(stop, int) or not isinstance(step, int):
raise TypeError("range() integers")
def __iter__(self):
return RangeIterator(self.start, self.stop, self.step)
def __repr__(self):
return f"Range({self.start}, {self.stop}, {self.step})"
class RangeIterator:
def __init__(self, start, stop, step):
self.current = start
self.stop = stop
self.step = step
def __iter__(self):
return self
def __next__(self):
if (self.step > 0 and self.current >= self.stop) or (self.step < 0 and self.current <= self.stop):
raise StopIteration
current = self.current
self.current += self.step
return current
# Example usage
for i in Range(1, 10, 2):
print(i) # Output: 1, 3, 5, 7, 9
Detailed Explanation
-
Initialization (
__init__method):- The
Rangeclass is initialized withstart,stop, andstepparameters. - If
stopisNone, thenstartis set to 0, andstoptakes the value of thestartparameter. - Validates that
stepis not zero and all arguments are integers.
def __init__(self, start, stop=None, step=1): if stop is None: self.start = 0 self.stop = start else: self.start = start self.stop = stop self.step = step if step == 0: raise ValueError("range() arg 3 must not be zero") if not isinstance(start, int) or not isinstance(stop, int) or not isinstance(step, int): raise TypeError("range() integers") - The
-
Iterator Protocol:
- The
__iter__method returns an iterator object,RangeIterator. - The
RangeIteratorclass implements the iterator protocol with__iter__and__next__methods.
def __iter__(self): return RangeIterator(self.start, self.stop, self.step) - The
-
Representation (
__repr__method):- The
__repr__method provides a string representation of theRangeobject.
def __repr__(self): return f"Range({self.start}, {self.stop}, {self.step})" - The
-
RangeIterator Class:
RangeIteratorclass is responsible for the actual iteration.- The
__next__method returns the next value in the sequence or raisesStopIterationwhen the sequence is exhausted.
class RangeIterator: def __init__(self, start, stop, step): self.current = start self.stop = stop self.step = step def __iter__(self): return self def __next__(self): if (self.step > 0 and self.current >= self.stop) or (self.step < 0 and self.current <= self.stop): raise StopIteration current = self.current self.current += self.step return current
Practical Example
for i in Range(1, 10, 2):
print(i) # Output: 1, 3, 5, 7, 9
Key Points
- Initialization: Handles different parameter combinations (
start,stop,step) and validates inputs. - Iterator Protocol: Implements the
__iter__and__next__methods to conform to the iterator protocol. - Efficient Iteration: Uses a separate
RangeIteratorclass to handle iteration efficiently.
Conclusion
The range() function in Python is a powerful and efficient way to generate sequences of numbers. Understanding its implementation helps appreciate how Python handles iteration and provides insights into writing custom iterators.
By examining this simplified implementation, we can see how the range() function initializes parameters, validates input, and iterates over a sequence of numbers, all while conforming to Python's iterator protocol.
Leave a Reply