PythonMastery

Use a generator when you only need one pass

sum([x for x in data]) builds a whole list first; sum(x for x in data) doesn't. Drop the brackets when you only read the values once.

Square brackets build a list: every value, in memory, before the next step starts. Round brackets build a generator, which hands over one value at a time and keeps nothing. If the values are read once, by sum, max, any or a for loop, the list is memory you paid for and never used.

Before

python
readings = range(1_000_000)

total = sum([r * 1.2 for r in readings])   # a million floats, held at once
print(round(total))
output
599999400000

After

Drop the square brackets. Inside a function call, the parentheses are already there.

python
readings = range(1_000_000)

total = sum(r * 1.2 for r in readings)     # one float at a time
print(round(total))
output
599999400000

Same answer. The difference is what sat in memory on the way.

See the difference

python
import sys

readings = range(1_000_000)
as_list = [r * 1.2 for r in readings]
as_gen = (r * 1.2 for r in readings)

print(f"list: {sys.getsizeof(as_list):,} bytes")
print(f"generator: {sys.getsizeof(as_gen):,} bytes")
example output · yours will differ
list: 8,448,728 bytes
generator: 200 bytes

On my machine the list is about 8 MB, and that's only the list's own slots: each float inside it is a separate object on top. The generator stays the same small size whatever the input, because it only remembers where it is. In the browser the exact numbers are smaller (it runs 32-bit Python), but the gap is the same kind.

Why it works

A generator runs your expression lazily: sum asks for the next value, the generator computes one, sum adds it, and that value can be thrown away. Nothing ever needs the million values at the same time, so nothing stores them.

When not to use it

A generator can be read once. The second pass gets nothing:

python
readings = (r for r in [3, 7, 5])
print(max(readings))
print(max(readings, default="empty"))
output
7
empty

If you need the values twice, need len(), indexing or sorting, keep the list. And for a small collection the saving is too small to matter: pick whichever reads better. The generators lesson goes further, into writing your own with yield.

Learn it properly: Generators: Lazy Iteration with yield, Comprehensions: Lists, Dicts, Sets, Generators