Back to blog
Coding2 min read

yield in Python

#python#generators#programming

Introduction

If you've been writing Python code, you will definitely find yourself writing functions to solve tasks.

For example, consider this function:

def function_1(x: int):
    for i in range(11):
        print(f'{x}*{i} = {x*i}')

Its behavior is straightforward — it prints a multiplication table. But what about this version?

def function_2(x: int):
    for i in range(11):
        yield f'{x}*{i} = {x*i}'

The keyword yield may not be obvious at first. Let's break it down.


return vs yield

function_1 with x=5 prints:

5*0 = 0
5*1 = 5
5*2 = 10
...
5*10 = 50

function_2 does not print anything immediately. Instead, yield suspends the function's execution and sends a value back to the caller — but retains enough state to resume exactly where it left off.

This means its code produces a series of values over time, rather than computing them all at once.


Generator Functions

The yield statement is only used in generator functions. When a generator function is called, it returns a generator iterator (a generator object). The body is executed lazily — only when you call next() on it:

gen = function_2(5)
print(next(gen))  # "5*0 = 0"
print(next(gen))  # "5*1 = 5"

Or iterate it:

for line in function_2(5):
    print(line)

How yield Works Internally

When yield is executed:

  1. The current state (local variables, instruction pointer, evaluation stack) is frozen
  2. The yielded value is returned to next()'s caller
  3. On the next next() call, execution resumes immediately after the yield

Advantages of yield

  • Memory efficient — values are generated one at a time, not stored all at once
  • Lazy evaluation — computation happens only when needed
  • Stateful — the generator remembers its position between calls

Disadvantages

  • Can be harder to debug without appropriate logging
  • Cannot be reused — a consumed generator is exhausted

Practical Example

Generators shine when working with large datasets:

def read_large_file(filepath):
    with open(filepath) as f:
        for line in f:
            yield line.strip()

# Processes lines one at a time — never loads the full file into memory
for line in read_large_file("huge_dataset.txt"):
    process(line)

The associated notebook for this post is available on GitHub.


References