1.2.11 · D5Introduction to Programming (Python)
Question bank — String indexing and slicing — `s[0]`, `s[-1]`, `s[2 - 5]`, `s[ - 2]`
True or false — justify
s[len(s)-1] and s[-1] always point to the same character.
True —
-1 is defined as len(s)-1 under the wrap-around rule, so they are literally the same address for any non-empty string.s[0] is the first character in every non-empty string, in every language.
False for the "every language" part — it is true in Python because Python counts from
0, but some languages count from 1. Within Python it is always the first character.For "PYTHON", s[-2] is the second character.
False — negatives count from the end, so
s[-2] is the second-from-last ('O', equal to s[4]), not the second from the front.s[2:5] and s[5] both touch the character at index 5.
False — the slice
s[2:5] stops before index 5 (half-open), so it never includes it; only s[5] reads that character directly.s[0:len(s)] returns the whole string.
True — start
0 includes the first char, stop len(s) is one past the last valid index, so every character 0..len(s)-1 is included.s[:] makes a full copy and is identical in value to s.
True — omitting start/stop/step means "whole thing," so the result equals
s. (For immutable strings it may even be the same object, but its value is guaranteed equal.)Slicing can raise an IndexError if the numbers are too big.
False — slicing clamps out-of-range bounds silently, so
s[6:99] returns ''; only single-character indexing like s[99] raises IndexError.s[::-1] and s[len(s)-1::-1] reverse the string identically.
True — with a negative step the omitted start defaults to the last index, which is exactly
len(s)-1, so both walk from the end to the front.You can fix a typo with s[0] = 'J' to get "JYTHON".
False — strings are immutable, so index-assignment raises
TypeError; you must build a new string, e.g. 'J' + s[1:]. See String immutability.s[2:2] returns the single character at index 2.
False — when start equals stop the range
[2, 2) is empty, so it returns ''. A slice needs stop strictly past start (in the step's direction) to contain anything.Spot the error
Someone writes s[1:4:0] to get "YTH". What breaks?
A step of
0 is illegal — it would mean "advance zero each time" (an infinite non-move), so Python raises ValueError: slice step cannot be zero. Use step 1.Someone claims s[4:1] returns "OHT" (going backward from 4 to 1).
Wrong — with the default positive step of
1, a start greater than stop yields an empty ''; to actually walk backward you must set a negative step, e.g. s[4:1:-1].Someone writes last = s[len(s)] to grab the last character.
Off-by-one — valid indices stop at
len(s)-1, so s[len(s)] raises IndexError. The last character is s[len(s)-1] or simply s[-1].A student says s[-0] gives the last character (mirror of s[-1]).
Wrong —
-0 is just 0, so s[-0] is s[0], the first character. There is no separate "negative zero" index.Someone reverses with s[-1:0:-1] and is surprised the "P" is missing.
The stop
0 is excluded, so the walk stops before index 0 and drops the first character. Correct reversal omits the stop entirely: s[::-1], or uses s[-1::-1].Someone counts the length of s[2:5] as 5 - 2 + 1 = 4.
The
+1 is the inclusive-range habit; slicing is half-open, so the count is exactly stop - start = 3. No +1.Why questions
Why does slicing exclude the stop index instead of including it?
Because half-open ranges make the count
stop - start clean and let adjacent slices tile perfectly: s[0:2] + s[2:5] == s[0:5] with no overlap or gap. This matches range()'s convention.Why does Python bother with negative indices when positive ones already reach every character?
They let you address positions from the end without first computing
len(s). s[-1] is shorter and off-by-one-proof compared to s[len(s)-1], especially inside expressions.Why does s[6:99] return '' instead of erroring like s[6] does?
Indexing must return one real character, so an impossible address is an error; slicing returns a collection, and "no characters in that range" is a perfectly valid answer — the empty string. See len() built-in for reasoning about bounds.
Why can you loop for c in s but not s[0] = 'X'?
Reading (iterating/indexing) never modifies the string, which is allowed; assignment would mutate it, and strings are frozen. See For loops over strings and String immutability.
Why does s[::2] start at index 0 and not index 1?
Omitting start with a positive step defaults it to
0 (the beginning). Step 2 then means "take one, skip one," giving indices 0, 2, 4.Why is s[i] equivalent to s[i - len(s)]?
Adding or subtracting a full length lands you on the same character because negative indexing is defined as wrapping around by
len(s); both expressions resolve to the same physical position.Edge cases
What does ""[0] (indexing an empty string) do?
It raises
IndexError — an empty string has no valid indices at all, since the range 0..len-1 is 0..-1, which is empty.What does ""[0:5] (slicing an empty string) do?
It returns
'' — slicing clamps to what exists, and nothing exists, so you get the empty string with no error.For a one-character string s = "A", what is s[0] versus s[-1]?
Both are
'A' — the single character is simultaneously the first (index 0) and the last (index -1), since len(s)-1 = 0.What does s[::-2] produce for "PYTHON", and why?
'NHY' — negative step reverses direction starting from the last char (index 5), stepping back by 2: indices 5, 3, 1 → N, H, Y.What is s[10:] for "PYTHON" (start past the end)?
'' — the start is clamped to the end of the string, leaving an empty range; slicing never errors on an oversized start.What does s[-100:] return for "PYTHON"?
The whole string
'PYTHON' — a negative start more extreme than -len(s) is clamped to the beginning (index 0), so the slice covers everything.Is s[2:5] a view into s or a brand-new string?
A brand-new independent string containing copies of those characters; because strings are immutable there is no live "view" you could edit through anyway.
Recall One-line summary of every trap
Indexing errors on bad addresses; slicing never errors and just clamps. Positive counts from 0, negative wraps from the end. stop is always excluded. Step 0 is illegal; a negative step reverses and re-interprets the defaults (start→last, stop→before-first). Strings are read-only.
Connections
- Lists indexing and slicing — every trap here applies identically to lists.
- String immutability — the root of all "you can't assign by index" traps.
- For loops over strings — reading without mutating.
- String methods (split, join, replace) — safe rebuilding instead of in-place edits.
- range() function — same half-open
[start, stop)logic. - len() built-in — the source of valid-index bounds
0..len-1.