Skip to Content
Course content

362: Optimizing Hot Loops

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Imagine you're a professional chef prepping for a massive banquet. You have to dice 500 carrots. If you walk all the way to the walk-in cooler, grab one single carrot, walk back to your station, dice it, and then walk back to the cooler for the next one, you're going to be there all night. You aren't spending your time dicing; you're spending your time walking.

In Python, a "hot loop" is that dicing station. It's the part of your code that runs millions of times. When a loop is "hot," the tiny inefficiencies that you normally ignore—like looking up a variable or calling a method—become massive bottlenecks. To optimize them, we have to stop "walking to the cooler" inside the loop and bring everything we need to the counter before we start.

The Hidden Cost of the Dot

Every time you use a dot in Python (like my_list.append()), Python has to perform a lookup. It asks, "Does my_list have an attribute called append?" If you do this ten million times, those lookups add up to a significant amount of wasted time. I've seen production scripts shave off seconds just by caching a method to a local variable.

# The slow way: looking up .append every iteration
results = []
for i in range(10_000_000):
    results.append(i * 2)

# The faster way: caching the method locally
results = []
append_func = results.append 
for i in range(10_000_000):
    append_func(i * 2)

By assigning results.append to append_func, we've moved the lookup outside the loop. Now, the loop just calls a local variable, which is much faster in the Python virtual machine.

Stop Recalculating the Constants

This is the most common mistake I see. Someone will put a calculation inside a loop that produces the same result every single time. It seems innocent, but it's a silent killer.

# Bad: calculating the radian conversion every time
import math
points = [1, 2, 3, 4, 5] # Imagine this is 1 million points
scaled_points = []
for p in points:
    scaled_points.append(p * (math.pi / 180))

# Good: move the invariant outside
conversion_factor = math.pi / 180
for p in points:
    scaled_points.append(p * conversion_factor)

That division math.pi / 180 doesn't change based on p. Moving it outside means we do the math once instead of a million times. It's a small change, but in a hot loop, it's the difference between a snappy app and one that feels frozen.

Letting C Do the Heavy Lifting

Python is an interpreted language, which means it's flexible but slow. However, many of Python's built-in functions are actually written in C. When you use a list comprehension or a built-in like sum() or map(), you're essentially handing the work over to a highly optimized C engine.

If you're manually looping through a list to add numbers or filter items, you're doing it the "slow" way. Try to push as much logic as possible into these built-ins. A list comprehension isn't just syntactic sugar; it's generally faster than a for loop with .append() because it optimizes the way the list is constructed internally.

# Slow: Manual loop
squares = []
for x in range(10_000_000):
    squares.append(x * x)

# Fast: List comprehension
squares = [x * x for x in range(10_000_000)]

I'll be honest: you shouldn't obsess over this for every single loop in your program. Most of your code isn't "hot." But once you identify that one function that's eating 80% of your CPU time, these are the first levers you should pull.




📋 Practical Task

Optimizing a High-Volume Coordinate Transformation Loop

You have a function that transforms a massive list of (x, y) coordinates by multiplying them by a scaling factor and shifting them by an offset. The current implementation is incredibly slow because it's doing too much work inside the loop.

Your Task: Rewrite the transform_coordinates function to optimize the hot loop. You must apply at least three techniques discussed in the lesson:

  • Move invariant calculations outside the loop.
  • Cache the list append method to a local variable.
  • Convert the final logic into a list comprehension for maximum speed.
import math

def transform_coordinates(coords, scale_factor):
    # This is the "hot" function
    transformed = []
    for x, y in coords:
        # Problem: The offset is recalculated every single iteration
        # Problem: .append is looked up every iteration
        offset = math.sqrt(scale_factor) * 1.5 
        transformed.append((x * scale_factor + offset, y * scale_factor + offset))
    return transformed

# Test data: 1 million coordinates
test_coords = [(i, i) for i in range(1_000_000)]
# Your optimized version should be significantly faster
result = transform_coordinates(test_coords, 2.5)
Rating
0 0

There are no comments for now.

to be the first to leave a comment.