Python Generators and Iterators: Interview Questions with Explained Answers 

Nov 5, 2026 | AuthenX

You explain that a generator produces values one at a time. Then the interviewer asks what happens when you convert the same generator to a list twice. Does it repeat the values, return an empty list or raise an error? 

Answering confidently requires understanding what has already been consumed. These Python generators and iterators interview questions connect definitions to code behaviour, practical choices and common mistakes. 

You should be comfortable with loops, functions and lists. If those still need work, start with these Python practice problems before tackling iterator state and lazy evaluation. For each example, predict the result before running it. 

Example validation: The Python code blocks were executed in Python 3.12.14. Displayed results and the deliberately raised exception were checked. Run each example separately; the file example requires the supplied sample input. 

1. What is the difference between an iterable, an iterator and a generator? 

An iterable can supply an iterator. An iterator produces successive items and tracks its progress. A generator object is a particular kind of iterator, created by a generator function or generator expression. 

Concept Example Key behaviour 
Iterable [10, 20] A list can supply a fresh iterator for another pass 
Iterator iter([10, 20]) Each next() advances its position 
Generator object (n * 2 for n in range(3)) Produces results as iteration requests them 

Every generator object is an iterator, and every iterator is iterable. However, not every iterable is an iterator: a list does not itself support next(). 

Also distinguish the function from its result. Calling a generator function creates the generator object you iterate over. 

2. How does a for loop use iter() and next()? 

A for loop obtains an iterator with iter(), repeatedly requests its next item and ends when StopIteration signals exhaustion. 

You can inspect that progression manually: 

items = iter([4, 8]) 
print(next(items))          # 4 
print(next(items))          # 8 
print(next(items, "done"))  # done 
 

Without the default argument, the final call would raise StopIteration. The default handles exhaustion; it does not suppress unrelated errors. 

3. How do you create a custom iterator? 

Implement __iter__() to return the iterator itself and __next__() to produce a value or raise StopIteration. 

class Countdown: 
    def __init__(self, start): 
        self.current = start 
 
    def __iter__(self): 
        return self 
 
    def __next__(self): 
        if self.current <= 0: 
            raise StopIteration 
        value = self.current 
        self.current -= 1 
        return value 
 
print(list(Countdown(3)))  # [3, 2, 1] 
 

This example assumes an integer starting value. Zero or a negative value produces no items. A class is useful when iteration belongs within an object with other behaviour; a generator can express a simple sequence more compactly. 

4. How does yield differ from return? 

yield produces a value and suspends execution, preserving local state. Resuming the generator continues after that suspension point. In a generator, return ends execution rather than yielding a final item. 

def steps(): 
    print("started") 
    yield 10 
    yield 20 
    return 
 
values = steps() 
print("created") 
print(next(values)) 
print(next(values)) 
print(next(values, "done")) 
 

Output: 

created 
started 
10 
20 
done 
 

Calling steps() does not execute its body. The first next() starts it. This timing matters when the body performs expensive work or could raise an exception. 

5. How does a generator expression differ from a list comprehension? 

A list comprehension builds its result list immediately. A generator expression calculates successive results as they are requested. 

squares_list = [n * n for n in range(3)] 
squares_generator = (n * n for n in range(3)) 
 
print(squares_list)             # [0, 1, 4] 
print(list(squares_generator))  # [0, 1, 4] 
 

The list supports indexing and repeated traversal. The generator provides a forward-only stream without those list operations. 

One detail worth explaining: the leftmost iterable expression in a generator expression is evaluated immediately. Laziness does not mean that every operation waits until the first next(). 

6. Can you reuse a generator after consuming it? 

An exhausted generator cannot be restarted. Partial consumption also changes what remains available: 

squares = (n * n for n in range(2, 5)) 
 
print(next(squares))  # 4 
print(list(squares))  # [9, 16] 
print(list(squares))  # [] 
 

The first call consumes one value. The first list() consumes the rest. The second finds nothing remaining. 

Create a new generator to repeat the calculation, or store the results if repeated access is required. Calling iter() on the existing generator returns that same object and does not reset it. 

7. Why can raising StopIteration inside a generator cause RuntimeError? 

In modern Python, a StopIteration exception that escapes a generator's body is converted into RuntimeError. 

def broken(): 
    yield 1 
    raise StopIteration 
 
list(broken())  # Raises RuntimeError 
 

Replace raise StopIteration with return to finish this generator normally. Reaching the end of the function also works. 

This differs from the custom iterator above, where raising StopIteration from __next__() is the correct end signal. The distinction prevents an unexpected exhaustion error inside generator code from silently truncating its output. 

CompeteX is PangaeaX's platform for practical data and technical competitions. When tackling Python coding challenges, identifying whether a task needs one pass or repeated access is a useful part of explaining your approach. The next questions practise that decision-making. 

8. What does yield from do? 

yield from delegates iteration to another iterable. Here it produces the individual values from each batch: 

def flatten_batches(batches): 
    for batch in batches: 
        yield from batch 
 
print(list(flatten_batches([[2, 4], [], [6]]))) 
# [2, 4, 6] 
 

This flattens one level, not arbitrarily nested data. For this example, a nested loop with yield would produce the same values. More advanced delegation can also pass generator-control operations and capture a subgenerator's return value. 

9. Are generators always faster or more memory-efficient? 

No. A generator can avoid storing every output at once, which helps when processing a large stream. It can still retain input objects and local state, and converting its output to a list creates that list in memory. 

A custom iterator can also produce values lazily. Laziness is not exclusive to generators. 

Choose based on the task: 

  • One-pass aggregation: A generator can feed values directly into sum(). 
  • Repeated traversal or indexing: Keeping a list may be appropriate. 
  • Speed-sensitive processing: Measure the complete workload rather than assuming a generator is faster. 

10. How would you process a large file with a generator? 

Iterate over the file and transform values as the consumer requests them. This example expects one integer quantity per line, ignores blank lines and yields only positive quantities. Invalid non-integer text raises ValueError. 

Create quantities.txt containing: 

10 
 
-2 
0 
7 
 

Then run: 

def positive_quantities(lines): 
    for line in lines: 
        if not line.strip(): 
            continue 
        quantity = int(line) 
        if quantity > 0: 
            yield quantity 
 
with open("quantities.txt", encoding="utf-8") as source: 
    total = sum(positive_quantities(source)) 
 
print(total)  # 17 
 

The code avoids loading the entire file or building a list of filtered quantities. Consumption happens inside the with block, while the file is open. An empty file produces a total of zero. 

A useful interview answer explains what the code produces, when it runs, what consumes its values and how it handles empty or invalid input. Practise changing one input and predicting the result before checking it. 

If you want to demonstrate that understanding beyond interview preparation, AuthenX is PangaeaX's skill authentication platform using AI-led interviews and portfolio screening. Explaining your technical choices clearly can support the evidence provided by your projects and practical work. 

Return to the opening question: converting the same exhausted generator to a list again produces an empty list. Being able to explain why, and when to create a fresh generator or keep a list instead, makes the answer useful beyond the interview. 

Stay Updated with PangaeaX

Subscribe to our newsletter for the latest insights, updates, and
opportunities in data science.