class CountUp:
def __init__(self, start, end):
self.current = start
self.end = end
def __iter__(self):
return self
def __next__(self):
if self.current > self.end:
raise StopIteration
value = self.current
self.current += 1
return value
for n in CountUp(1, 5):
print(n, end=' ') # 1 2 3 4 5class Squares:
def __init__(self, n):
self.n = n
self.i = 0
def __iter__(self):
return self
def __next__(self):
if self.i >= self.n:
raise StopIteration
self.i += 1
return (self.i - 1) ** 2
sq = Squares(4)
it = iter(sq) # Get the iterator
print(next(it)) # 0
print(next(it)) # 1
print(next(it)) # 4
print(next(it)) # 9
# print(next(it)) # StopIterationclass MyRange:
def __init__(self, n):
self.n = n
self.i = 0
def __iter__(self):
return self
def __next__(self):
if self.i >= self.n:
raise StopIteration
val = self.i
self.i += 1
return val
r = MyRange(3)
print(list(r)) # [0, 1, 2]
print(list(r)) # [] — exhausted!class RangeIterable:
def __init__(self, n):
self.n = n
def __iter__(self):
return RangeIterator(self.n) # NEW iterator each time!
class RangeIterator:
def __init__(self, n):
self.n = n
self.i = 0
def __iter__(self):
return self
def __next__(self):
if self.i >= self.n:
raise StopIteration
val = self.i
self.i += 1
return val
r = RangeIterable(3)
print(list(r)) # [0, 1, 2]
print(list(r)) # [0, 1, 2] — works again!class Reverse:
def __init__(self, data):
self.data = data
self.index = len(data)
def __iter__(self):
return self
def __next__(self):
if self.index <= 0:
raise StopIteration
self.index -= 1
return self.data[self.index]
for ch in Reverse('hello'):
print(ch, end='') # ollehCreate a `FibIterator` class that generates Fibonacci numbers up to a `limit` parameter. Implement the full iterator protocol. Create a `FibIterable` class whose `__iter__` returns a NEW `FibIterator` each time (so it's reusable). Demonstrate: iterating with for loop, converting to list twice (both should work), and using next() manually.