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
Range
class is initialized withstart
,stop
, andstep
parameters. - If
stop
isNone
, thenstart
is set to 0, andstop
takes the value of thestart
parameter. - Validates that
step
is 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
RangeIterator
class 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 theRange
object.
def __repr__(self): return f"Range({self.start}, {self.stop}, {self.step})"
- The
-
RangeIterator Class:
RangeIterator
class is responsible for the actual iteration.- The
__next__
method returns the next value in the sequence or raisesStopIteration
when 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
RangeIterator
class 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