So what is yield in Python? It’s a keyword that turns a function into a generator: instead of returning one result and ending, the function hands back a value, pauses, and picks up where it left off the next time you ask for a value:
def countdown(n):
while n > 0:
yield n
n -= 1
list(countdown(3)) # [3, 2, 1]
The prints inside each generator below show exactly when its code runs. I ran them all on Python 3.12.5.
We’ll trace how a generator pauses, loop over one, compare memory with a list, process a big file lazily, build an infinite sequence, and look at yield from and send().
How yield works: a generator step by step
Calling a generator function doesn’t run it; you get a generator object. Each next() runs the body until the next yield, then pauses there:
def countdown(n):
print(" (starting)")
while n > 0:
yield n # hand back a value and pause right here
n -= 1
print(" (finished)")
gen = countdown(3)
print(type(gen).__name__) # calling it didn't run the body yet
print(next(gen))
print(next(gen))
print(next(gen))
try:
next(gen)
except StopIteration:
print("StopIteration: nothing left")
Output:
generator
(starting)
3
2
1
(finished)
StopIteration: nothing left

next(). When the function ends, the generator raises StopIteration.Local variables like n survive between calls, because the function’s frame is frozen at the yield, not thrown away.
Using a generator in a for loop
A for loop calls next() for you and stops cleanly at StopIteration. Just remember a generator can be consumed only once:
def even_prices(prices):
for p in prices:
if round(p * 100) % 2 == 0:
yield p
menu = [4.50, 2.75, 3.20, 9.99, 12.00]
for price in even_prices(menu): # for loops call next() for you
print(f"${price:.2f}")
gen = even_prices(menu)
print(list(gen)) # first pass uses it up...
print(list(gen)) # ...second pass is empty
Output:
$4.50
$3.20
$12.00
[4.5, 3.2, 12.0]
[]
If you need the values twice, call the generator function again or store them with list(). The loop side is covered in the Python for loop guide.
Why use yield instead of returning a list?
A list holds every value at once. A generator produces them one at a time, so its size stays tiny no matter how many values it will produce:
import sys
squares_list = [n * n for n in range(1_000_000)]
squares_gen = (n * n for n in range(1_000_000)) # generator expression
print(f"list: {sys.getsizeof(squares_list):>10,} bytes")
print(f"generator: {sys.getsizeof(squares_gen):>10,} bytes")
print("same total:", sum(squares_list) == sum(n * n for n in range(1_000_000)))
Output:
list: 8,448,728 bytes
generator: 200 bytes
same total: True

(n * n for n in ...) with parentheses is a generator expression, the one-line form of a generator function. See Python for loop in one line for more.
Processing a large file with yield
This is where I find generators shine in real work. Reading a file line by line inside a generator keeps memory flat even for files with millions of rows:
with open("orders_2026.csv", "w", encoding="utf-8") as f:
f.write("id,city,total\n")
for i in range(1, 100_001):
f.write(f"{i},{'Austin' if i % 3 else 'Denver'},{i % 50 + 0.99}\n")
def read_orders(path):
with open(path, encoding="utf-8") as f:
next(f) # skip the header
for line in f: # one line in memory at a time
order_id, city, total = line.rstrip().split(",")
yield city, float(total)
denver = sum(total for city, total in read_orders("orders_2026.csv") if city == "Denver")
print(f"Denver revenue: ${denver:,.2f}")
Output:
Denver revenue: $849,682.67

The with block stays open while the generator runs and closes when it finishes. More on that in Python with open() as file.
Infinite generators and yield from
A generator can loop forever, because it only does work when asked. itertools.islice() takes just the first few values. yield from passes along everything from another iterable:
from itertools import islice
def invoice_numbers(start=1001):
n = start
while True: # infinite, but only runs as far as you ask
yield f"INV-{n}"
n += 1
print(list(islice(invoice_numbers(), 5)))
def chain_all(*iterables):
for it in iterables:
yield from it # delegate to another iterable
print(list(chain_all(["TX", "CA"], ("NY",), ["AZ"])))
Output:
['INV-1001', 'INV-1002', 'INV-1003', 'INV-1004', 'INV-1005']
['TX', 'CA', 'NY', 'AZ']

yield from.A while True loop is safe here because the caller decides when to stop. See infinite loops in Python for the regular kind.
Sending values into a generator
yield can also receive values. send() resumes the generator and makes the yield expression evaluate to what you sent, which suits running calculations:
def running_average():
total, count = 0.0, 0
average = None
while True:
value = yield average # receive a value from send()
total += value
count += 1
average = total / count
avg = running_average()
next(avg) # prime it: run to the first yield
for sale in [120.00, 80.00, 100.00]:
print(f"sale ${sale:.2f} -> running average ${avg.send(sale):.2f}")
Output:
sale $120.00 -> running average $120.00
sale $80.00 -> running average $100.00
sale $100.00 -> running average $100.00
In my own code, send() shows up far less often than plain iteration, but it’s handy for stateful pipelines like this running average.
yield vs return
return | yield | |
|---|---|---|
| Function becomes | A normal function | A generator function |
| Values produced | One, then the function ends | Many, one per next() |
| State between calls | Lost | Kept (paused frame) |
| Memory for many values | Needs a full list | Constant |
| Can be looped twice | Yes (the list) | No, it’s used up |
More on functions and iteration in Python:
- What does enumerate do in Python
- Lambda functions in Python
- range vs xrange in Python
- reduce() function in Python
Frequently asked questions
What is yield in Python?
It’s a keyword that makes a function a generator. Each yield hands a value to the caller and pauses the function until the next value is requested.
What’s the difference between yield and return?
return sends back one value and ends the function. yield sends back a value and pauses, so the function can produce many values over time.
How do I get all values from a generator?
Loop over it, or call list(gen). Remember it can only be consumed once.
What is StopIteration?
The signal a generator raises when it has no more values. for loops handle it automatically.
What does yield from do?
It yields every value from another iterable or generator, so you don’t need a nested loop.
Where is yield documented?
See Yield expressions in the Python language reference.

Bijay Kumar is a 13-time Microsoft MVP with more than 18 years in software development, and the founder of Python Guides and TSinfo Technologies. He started out building .NET and SharePoint solutions at HP, TCS and KPIT before moving into Python, machine learning and AI, and he also builds web apps with TypeScript and React. He writes the tutorials here himself, and every example is run before publishing so you see the real output. More about Bijay · Microsoft MVP profile · LinkedIn