Compare the memory use of a Python list comprehension with a generator expression.
The difference is dramatic, and it comes down to eagerness. A list comprehension builds every value immediately; a generator expression produces each one only when it is asked for.
import sys
data = range(1_000_000)
as_list = [n * 2 for n in data]
as_gen = (n * 2 for n in data)
print(sys.getsizeof(as_list)) # 8448728 - about 8 MB
print(sys.getsizeof(as_gen)) # 200 - a tiny generator object
print(len(list(as_gen))) # 1000000The list occupies roughly 8.4 megabytes just for the list of pointers, and that figure does not count the million integer objects it refers to. The generator object is 200 bytes, because all it holds is a reference to the range and a position in it.
The last line is the catch. Converting the generator to a list gives you the same million values and the same 8 megabytes — the memory was never saved, it was merely deferred. The saving is real only when you consume the values and let them go as you go.
That is the honest framing for an interview: a generator does not use less memory to hold the same data. It uses less memory because it never holds all the data at once, which only helps if you process the stream as it arrives rather than collecting it.