Slicing

RoadmapsPython Backend

Overview

Slicing extracts a sub-sequence with `sequence[start:stop:step]`. Any of the three can be omitted: `start` defaults to 0, `stop` defaults to the sequence's length, `step` defaults to 1. `stop` is exclusive, so a slice covers a half-open interval — `items[2:5]` returns indices 2, 3, 4, never 5. That's why `len(items[a:b]) == b - a` (clamped to the sequence bounds), a handy sanity check. Negative indices count from the end (`items[-1]` is the last element), and negative indices work inside slices too: `items[-3:]` means 'last 3 elements'. A negative `step` reverses direction: `items[::-1]` reverses the whole sequence — it walks from the end to the start. The critical property for backend code: slicing ALWAYS returns a new list (or string, or tuple) — it never returns a view into the original, and it never raises `IndexError` even if the bounds are out of range. `items[100:200]` on a 3-element list just returns `[]`, silently. That's convenient for pagination logic (no bounds-checking needed) but dangerous if you actually expected an error to catch a bad offset. page = items[offset:offset + limit] # never crashes, even if offset is way past the end page is a NEW list — mutating page does not touch items

Slicing is the standard tool for in-memory pagination and batching before it's worth pushing that logic into a DB query, and its never-raises, always-copies behavior is exactly what makes it safe to reach for without extra bounds-checking or defensive-copy code.

Where used: In-memory pagination: `results[offset:offset + page_size]`, String truncation for logs: `message[:200] + '...' if len(message) > 200 else message`, Reversing a sequence: `history[::-1]` to show most-recent-first

Why learn this

Code walkthrough

items = [1, 2, 3, 4, 5, 6, 7]

page = items[2:2+3]
print(page)

page.append(999)
print("page:", page)
print("items:", items)

Focus: Watch that mutating `page` after the slice has zero effect on `items` — the slice created a fully independent list, it did not hand back a window into the original.

Common mistakes

Glossary

slice
A `start:stop:step` expression inside `[]` that extracts a sub-sequence from a list, tuple, or string, returning a NEW object rather than a reference into the original. Example: `items[2:5]`
half-open interval
A range that includes its start but excludes its end — `[start, stop)`. Python slices work this way: `items[2:5]` includes index 2, 3, 4 but not 5, so `stop - start` always equals the slice's length. Example: `items[0:0]` is empty

Recall questions

Understanding checks

What does this print?

[30, 40, 50] [10, 20, 30] [50, 40, 30, 20, 10]

`items[-3:]` means 'from the 3rd-from-last element to the end' -> last 3 elements. `items[:-2]` means 'from the start up to (not including) the 2nd-from-last' -> drops the last 2. `items[::-1]` uses step -1, which walks the whole sequence backward, reversing it.

A function does `page = data[offset:offset+limit]` where `offset=1000` and `data` has 5 elements. It returns `[]` with no error. Is this a bug, and how would you detect 'offset is beyond the data' if the caller needs to know?

Not a bug in the slicing itself — this is correct, documented slice behavior. If the caller needs to distinguish 'valid empty result' from 'offset out of range', that check has to be explicit: compare `offset` against `len(data)` before or after slicing, since the slice operation itself will never signal it.

Slicing's silent clamping is a feature for iteration convenience, but it means bounds validation is the caller's job whenever an out-of-range offset is meaningfully different from a legitimately empty page.

Practice tasks

Continue learning

Previous: Slicing

Next: Comprehensions

Return to Python Backend Roadmap