Mid-Level Core Language 5 min read

List Comprehensions vs Generators in Python

The Interview Question

What is the difference between a list comprehension and a generator expression? When would you use each?

Expert Answer

A list comprehension creates the entire list in memory at once. A generator expression produces values one at a time, on demand — this is called lazy evaluation. The syntax difference is minimal: square brackets for lists, parentheses for generators. The behavioral difference is massive. A list comprehension that processes 10 million rows creates a 10-million-element list in memory. A generator expression processes one row at a time, using constant memory regardless of input size. Use list comprehensions when you need random access, need to iterate multiple times, or the dataset fits comfortably in memory. Use generators when processing large datasets, streaming data, building pipelines, or when you only need to iterate once. Generator functions (using yield) extend this pattern to more complex logic — each yield pauses the function, and next() resumes it.

Key Points to Hit in Your Answer

  • List comprehension: [x for x in range(n)] — builds full list in memory
  • Generator expression: (x for x in range(n)) — produces values lazily
  • Generators use O(1) memory regardless of input size
  • Generators can only be iterated once — they're exhausted after one pass
  • yield pauses function execution and saves state; next() resumes it
  • Chain generators for memory-efficient data pipelines

Code Example

# Memory comparison
import sys

list_comp = [i ** 2 for i in range(1_000_000)]
gen_expr = (i ** 2 for i in range(1_000_000))

sys.getsizeof(list_comp)  # ~8,448,728 bytes (8MB)
sys.getsizeof(gen_expr)   # ~200 bytes (constant!)

# Generator function with yield
def read_large_file(path):
    with open(path) as f:
        for line in f:
            yield line.strip()  # one line at a time

# Pipeline — no intermediate lists in memory
def pipeline(path):
    lines = read_large_file(path)               # generator
    non_empty = (l for l in lines if l)          # generator
    parsed = (json.loads(l) for l in non_empty)  # generator
    active = (r for r in parsed if r['active'])  # generator
    
    for record in active:  # only NOW does processing happen
        process(record)

What Interviewers Are Really Looking For

Demonstrating the memory difference with actual numbers (8MB vs 200 bytes) is compelling. Showing a generator pipeline where no intermediate lists are created demonstrates real-world usage. If asked 'what happens if you iterate a generator twice?', you should know it produces nothing the second time — it's exhausted.

Practice This Question with AI Grading

Reading about interview questions is a start — but practicing with real-time AI feedback is how you actually get better. Goliath Prep grades your answers instantly and tells you exactly what you're missing.

Start Practicing Free →