PYTHON

Python yield Keyword: Syntax, Usage, and Examples

The yield keyword turns a Python function into a generator that produces values one at a time instead of returning them all at once. It’s perfect when you want to iterate over results lazily, especially for large or ongoing data.


How to Use the yield Keyword in Python

You use yield inside a function body. The moment Python sees yield, it treats the function as a generator function.

Basic syntax

defgenerator_function():
yield value

A generator function returns a generator object, not a final value.

defsay_hello():
yield"Hello"
yield"Hi again"

g = say_hello()
print(g)# <generator object ...>

To get values out of it, you iterate:

for messagein say_hello():
print(message)

yield vs return

return ends the function immediately and sends back one final value.

yield pauses the function and sends back a value, then continues later from the same spot.

defnumbers_with_return():
return1
return2# never runs

defnumbers_with_yield():
yield1
yield2# runs later

What happens after yield

When Python hits a yield statement:

  1. It returns the yielded value to the caller
  2. It saves the function’s state (local variables, current position)
  3. It pauses the function until the next request

That “pause and continue” behavior is what makes generators feel like a controlled faucet instead of dumping the whole bucket.

Using yield in a loop

Most generator functions use yield inside a loop:

defcount_up_to(limit):
    current =1
while current <= limit:
yield current
        current +=1

for nin count_up_to(5):
print(n)

Getting the next value with next()

You can manually pull values using next().

defsteps():
yield"Step 1"
yield"Step 2"
yield"Step 3"

g = steps()

print(next(g))# Step 1
print(next(g))# Step 2
print(next(g))# Step 3

After it runs out, Python raises StopIteration:

print(next(g))# StopIteration error

A safe way to handle that is to iterate with a for loop instead of calling next() directly.


When to Use the yield Keyword

yield is most useful when you want results to arrive gradually, or when storing everything in memory would be wasteful.

1) Working with large data without loading it all at once

A generator can produce items one by one, which keeps memory usage low.

Example: generate a lot of numbers without creating a huge list:

defbig_range(limit):
    i =0
while i < limit:
yield i
        i +=1

This pattern matters in real programs, like processing log files or large datasets for analysis.

2) Streaming data or infinite sequences

Some data never really “ends.” Generators work nicely because they can keep going until you choose to stop.

Example: an endless ID generator:

defid_generator(start=1):
    current = start
whileTrue:
yield current
        current +=1

You can use it in controlled ways, like taking only the first 5 IDs.

3) Building your own iterator-like behavior

yield helps you create custom iteration rules without writing a full iterator class.

Example: walk through a nested structure or perform an on-demand traversal.

If you’ve ever thought “I want to loop over this, but in a special way,” that’s generator territory.

4) Writing clearer pipelines

Generators can create pipelines where one generator feeds another. That can keep your code simple and readable.

Think: “Take input, filter it, transform it, output it,” step by step.


Examples of the yield Keyword in Python

Let’s go through practical examples you’ll actually run into.

Example 1: Generating even numbers

Instead of building a list of evens, you can yield them as you go.

defevens_up_to(limit):
for ninrange(limit +1):
if n %2 ==0:
yield n

for nin evens_up_to(10):
print(n)

This prints 0, 2, 4, 6, 8, 10.


Example 2: Reading a file line by line

Files can be huge, so loading the whole thing into memory is a bad deal.

A generator lets you “sip” lines instead of chugging the whole file.

defread_lines(filepath):
withopen(filepath,"r", encoding="utf-8")as file:
for linein file:
yield line.strip()

Then:

for linein read_lines("notes.txt"):
if line:
print(line)

This style works great for logs, exports, and CSV-like formats.


Example 3: Filtering values lazily

You can build a generator that filters incoming data without producing a new list.

deffilter_long_words(words, min_length):
for wordin words:
iflen(word) >= min_length:
yield word

words = ["cat","elephant","bee","giraffe","ant"]
for win filter_long_words(words,4):
print(w)

Output:

  • elephant
  • giraffe

Example 4: Yielding results from another generator

The yield from syntax lets one generator delegate to another generator.

deffirst_part():
yield"A"
yield"B"

defsecond_part():
yield"C"
yield"D"

deffull_sequence():
yieldfrom first_part()
yieldfrom second_part()

for itemin full_sequence():
print(item)

This prints A, B, C, D.

yield from is cleaner than writing two separate loops manually.


Example 5: Generating chunks of data

Sometimes you want to process items in chunks, like batching API calls or splitting work into groups.

defchunks(items, size):
    batch = []
for itemin items:
        batch.append(item)
iflen(batch) == size:
yield batch
            batch = []
if batch:
yield batch

numbers = [1,2,3,4,5,6,7]
for groupin chunks(numbers,3):
print(group)

Output:

  • [1, 2, 3]
  • [4, 5, 6]
  • [7]

Learn More About the yield Keyword

Generators are easy to use, but they have a few important behaviors worth knowing.

yield creates a generator object

Calling a generator function does not run the code immediately. It prepares it.

defgreet():
print("Starting generator")
yield"Hello"
print("Ending generator")

g = greet()# nothing prints yet

The function starts running only when you pull from it:

print(next(g))

That prints:

  • Starting generator
  • Hello

Then later:

try:
print(next(g))
except StopIteration:
print("Generator finished")

You’ll see:

  • Ending generator
  • Generator finished

Generators can only be consumed once

A list can be looped through again and again. A generator can’t.

defsmall():
yield1
yield2

g = small()

print(list(g))# [1, 2]
print(list(g))# []

Once the generator is exhausted, it stays exhausted.

If you need the values again, you must create a new generator instance.

Generator expressions vs yield

Generator expressions are like list comprehensions, but they produce values lazily.

squares = (n * nfor ninrange(5))
for valuein squares:
print(value)

That’s similar to writing a generator function with yield, but generator functions are better when the logic is more complex or needs multiple steps.

Returning a value from a generator

You can use return in a generator function, but it ends the generator.

defdemo():
yield1
return
yield2# never runs

Technically, return some_value is also possible in a generator, but that value gets attached to the StopIteration exception. Most people don’t use that pattern in everyday code, so sticking to plain return is usually best.

Using yield to build memory-friendly loops

If you write code that handles:

  • thousands of items
  • large files
  • streaming data
  • repeated transformations

Generators help you avoid building huge lists in memory. Your program stays smoother, and you often get results earlier.

Common beginner mistake: trying to index a generator

Generators don’t support indexing like lists.

This won’t work:

g = (nfor ninrange(10))
print(g[0])

Instead, convert it to a list first if you really need indexing:

g = (nfor ninrange(10))
values =list(g)
print(values[0])

Or pull one value at a time with next().


Summary

The yield keyword lets you create generator functions that produce values one at a time. Use it when you want memory-friendly iteration, streaming-style results, or clean pipelines that don’t need to store everything upfront. Generators are simple to write, easy to read, and surprisingly powerful once you start using them in real projects.