Pynsights — Advanced Python Interactive Guide<br>TopicsBenchmarks
Understand.<br>Visualize.<br>Master.
Python in Depth
An interactive engineering reference for Python internals
Quick note Copy is the hidden cost.<br>:)
TABLE OF CONTENTS
1. Sequences & matching<br>2. Language model<br>3. Dictionaries & sets<br>4. Memory & throughput<br>5. Data classes & types<br>6. Production runtime
1.1Readable slicing in production code<br>A slice with half-open bounds is the difference between `a[:n]` + `a[n:]` composing perfectly and staring at off-by-one errors at 2 AM.<br>WHAT IT IS<br>Think of slices like train cars: each car has a number, but you board at the front edge of car N and get off at the front edge of car M. The car at the stop edge stays outside the ride. That is half-open: start included, stop excluded.<br>The beauty is composition. If you split a list at index n, `a[:n]` and `a[n:]` cover every element exactly once. No overlap, no gap. That is the point of half-open ranges.
HOW IT WORKS<br>1Python normalizes omitted bounds and negative indices against the sequence length before performing the slice.<br>2For built-in sequences, slicing creates a new container and copies references (or values for flat types) for the selected range. List slicing allocates proportional to the slice length.<br>3Stride values change traversal order. `[::-1]` reverses. `[::2]` skips every other. Stride still allocates a copy, even if you are skipping elements.
WHEN TO USE IT<br>Use slicing when position ranges are the natural model and the caller already thinks in offsets.<br>Name common slices with `slice(0, 8)` instead of bare `[:8]`, so the name carries domain meaning.<br>Avoid large slices in hot paths when an iterator or view approach is enough.
KEY TAKEAWAYS<br>Half-open ranges eliminate off-by-one drift when composing adjacent slices.<br>List slicing allocates every time. The copy is the hidden cost.<br>Negative strides are expressive but still pay full allocation cost.
TRY IT OUT!
items = [10, 20, 30, 40, 50, 60]<br>middle = items[2:5]<br>reverse_every_other = items[::-2]<br>print(middle, reverse_every_other)<br>See visual→Open full guide
MEASURED NOTEBOOKMeasured
Measured materialized slice copies<br>This notebook compares native list slicing with list(islice(...)) when both paths must return the same copied list from a 1,000,000-item source list. It measures throughput across 1k, 10k, and 100k copied spans and shows whether either path allocates less result memory.<br>Winnerlist[start:stop] — 12.2x faster than list(islice(...)) @ 100k<br>RELATED GUIDE<br>Readable slicing in production code<br>Materialized copy time by copied span<br>0.00 µs950.0 µs1900.0 µs1k10k100klist[start:stop] copy<br>list(islice(...)) materialized
METRICS<br>Faster copy pathlist[start:stop]<br>Speed gap @ 100k12.2x faster<br>Result allocation @ 100ktie: 781.3 KiB each<br>Source list size1,000,000 items
NOTES<br>What this tests — both code paths copy the same span from a 1M-element source list. One uses native `list[start:stop]`, the other builds a new list via `list(islice(...))`. The question is which is faster and whether they allocate differently.<br>Why native slicing won — `list[start:stop]` is implemented entirely in C inside `listobject.c`. It preallocates the result list, copies references in a tight C loop, and increments each element's reference count. `itertools.islice` is also a C iterator, but `list(islice(...))` still has to advance an iterator and append one element at a time.<br>The surprise — the result list is identical in memory both ways. `list[start:stop]` wins on CPU time, not allocation. The speed gap grows with span size because per-element iterator and append overhead scales linearly with the number of elements yielded.<br>Takeaway — use native slicing for materialized copies. Use `islice` only when you need lazy iteration over a range without allocating result storage.
TEST ENVIRONMENT<br>Python Version3.12.3<br>Machinex86_64
Contribute