Each instruction is a layer; each layer is cached
Docker checks each instruction against the cache. If the instruction and its inputs (files referenced by COPY, args used in RUN) haven't changed, the cached layer is reused. The first instruction whose cache misses busts every later layer.
The cache-busting bug
If you COPY . . before RUN pip install, then any code change re-copies everything, busts the install layer, and reinstalls every dependency. Slow. Annoying. Easily avoidable.
The fix: dependencies before code
Copy the dependency manifest (requirements.txt, package.json, Cargo.toml) first. Install. Then copy the rest of the source. Code changes don't bust the dependency layer.