Tutorials Logic, IN +91 8092939553 info@tutorialslogic.com
FAQs Support
Navigation
Home About Us Contact Us Blogs FAQs
Tutorials
All Tutorials
Services
Academic Projects Resume Writing Interview Questions Website Development
Compiler Tutorials

Iterators & Generators in Python

Iterators

An iterator is any object that implements __iter__() and __next__(). When you use a for loop, Python calls these methods behind the scenes.

Iterators
# Built-in iterables
nums = [1, 2, 3]
it = iter(nums)          # get iterator from list
print(next(it))          # 1
print(next(it))          # 2
print(next(it))          # 3
# next(it)               # StopIteration!

# for loop does this automatically
for n in [1, 2, 3]:
    print(n)

# Custom iterator class
class CountUp:
    def __init__(self, start: int, stop: int):
        self.current = start
        self.stop = stop

    def __iter__(self):
        return self

    def __next__(self):
        if self.current > self.stop:
            raise StopIteration
        value = self.current
        self.current += 1
        return value

for n in CountUp(1, 5):
    print(n)   # 1 2 3 4 5

Generators with yield

A generator is a function that uses yield instead of return. It produces values one at a time, pausing between each — memory-efficient for large sequences.

Generator Functions
def count_up(start: int, stop: int):
    current = start
    while current <= stop:
        yield current        # pause here, return value
        current += 1         # resume here on next call

gen = count_up(1, 5)
print(next(gen))   # 1
print(next(gen))   # 2

for n in count_up(1, 5):
    print(n)       # 1 2 3 4 5

# Fibonacci generator — infinite sequence
def fibonacci():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

fib = fibonacci()
print([next(fib) for _ in range(10)])
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

# Generator vs list — memory comparison
import sys
gen_size  = sys.getsizeof(x for x in range(1_000_000))
list_size = sys.getsizeof([x for x in range(1_000_000)])
print(f"Generator: {gen_size} bytes")    # ~200 bytes
print(f"List:      {list_size} bytes")   # ~8 MB!

Generator Expressions

Like list comprehensions but with parentheses — lazy evaluation, no memory overhead.

Generator Expressions
# List comprehension — creates entire list in memory
squares_list = [x**2 for x in range(10)]

# Generator expression — lazy, one value at a time
squares_gen = (x**2 for x in range(10))

# Use directly in functions
total = sum(x**2 for x in range(1, 101))   # sum of squares 1-100
print(total)   # 338350

# Find first match without building full list
first_even = next(x for x in range(100) if x % 7 == 0 and x > 10)
print(first_even)   # 14

# Chain generators (pipeline)
numbers = range(1, 20)
evens = (x for x in numbers if x % 2 == 0)
squared = (x**2 for x in evens)
print(list(squared))  # [4, 16, 36, 64, 100, 144, 196, 256, 324]

yield from

yield from
# yield from — delegate to another iterable
def flatten(nested):
    for item in nested:
        if isinstance(item, list):
            yield from flatten(item)   # recurse into sub-lists
        else:
            yield item

data = [1, [2, 3], [4, [5, 6]], 7]
print(list(flatten(data)))   # [1, 2, 3, 4, 5, 6, 7]

# Combine multiple generators
def chain(*iterables):
    for it in iterables:
        yield from it

result = list(chain([1, 2], [3, 4], [5, 6]))
print(result)   # [1, 2, 3, 4, 5, 6]

# itertools — powerful iterator tools
import itertools

# islice — take first n items from any iterable
fib_10 = list(itertools.islice(fibonacci(), 10))
print(fib_10)   # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

# chain — combine iterables
combined = list(itertools.chain([1, 2], [3, 4], [5]))
print(combined)  # [1, 2, 3, 4, 5]

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.