Tutorials Logic, IN info@tutorialslogic.com
Navigation
Home About Us Contact Us Blogs FAQs
Tutorials
All Tutorials
Services
Academic Projects Resume Writing Website Development
Practice
Quiz Challenge Interview Questions Certification Practice
Tools
Online Compiler JSON Formatter Regex Tester CSS Unit Converter Color Picker
Compiler Tools

Iterators Generators in Python yield: Tutorial, Examples, FAQs & Interview Tips

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.