Output Puzzles: Strings, Slicing and Immutability
40 min · Intermediate
Need help? Ask a tutor on WhatsApp (opens in a new tab)String snippets are the most common output questions. The traps are small: a slice that stops one short, a method whose result is thrown away, or a character that is longer than it looks. Know the slice rules and that strings never change in place.
Slicing rules
A slice is a part of a sequence taken with [start:stop:step]. The stop position is excluded, negative positions count from the end, and a slice that goes past the end is cut short instead of failing.
text[start:stop:step] takes characters from start up to, but not including, stop. Negative numbers count from the end. A slice never raises an error for an out-of-range stop; it just returns less.
s = "python"print(s[1:4], s[-3:], s[::-1])print(len(s[10:]), s[2:99])print(s[::2])Example 1 · Slices that reverse, skip and stop short
word = "interview"print(word[2:5])print(word[-4:])print(word[::2])print(word[::-1])print(word[3:100])ter view itriw weivretni erview
What this code does
- The stop index is excluded, so
[2:5]has 3 characters. [-4:]starts 4 from the end. Step 2 takes every second letter.- A stop beyond the end does not raise an error.
This prints yth hon nohtyp, then 0 thon, then pto. s[::-1] walks backward through the whole string, so it reverses it.
Strings are immutable
Immutable means an object cannot be changed after it is created. A string method returns a new string, and assigning to a character such as s[0] = "b" raises a TypeError.
A string cannot be changed after it is created. Methods such as upper() and replace() return a new string. If you do not keep the result, nothing changes.
s = "cat"s.upper()print(s)t = ss += " food"print(t, s)# s[0] = "b" would raise TypeErrorExample 2 · Methods return new strings
title = " Data Science "cleaned = title.strip().upper()print(repr(title))print(repr(cleaned))print(title.strip() == "Data Science")' Data Science ' 'DATA SCIENCE' True
What this code does
titlenever changes; each method hands back a new string.- Chain the methods, or assign the result to a name to keep it.
The first line prints cat because the result of upper() was dropped. After s += ..., t still points to the old cat, so it prints cat cat food.
Split, join, find and count
split() with no argument breaks on any run of spaces and drops empty pieces. split(",") keeps empty pieces. find returns -1 when the text is missing, while index raises an error.
print(" a b ".split())print("a,b,,c".split(","))print("-".join(["x", "y"]))print("banana".find("na"), "banana".count("na"))Example 3 · Split and join round trip
line = "2026-11-03"parts = line.split("-")print(parts)print("/".join(reversed(parts)))print("a-b-c".split("-", 1))['2026', '11', '03'] 03/11/2026 ['a', 'b-c']
What this code does
splitreturns a list of strings, not numbers.reversedflips the list, thenjoinglues it with a new separator.- A second argument limits the number of splits.
This prints ['a', 'b'], ['a', 'b', '', 'c'], x-y and 2 2. join is called on the separator, not on the list.
Comparison, formatting and Unicode
Strings compare character by character using their code points, so "10" < "9" is true and an uppercase letter is smaller than a lowercase one. len counts characters, but encode() gives bytes, and one character can use several bytes.
print("10" < "9", "Z" < "a")print(len("héllo"), len("héllo".encode()))print(f"[{'Asha':>6}] [{3.14159:.2f}]")Example 4 · Characters are not bytes
name = "café"print(len(name), len(name.encode()))print("é" == "e\u0301", len("e\u0301"))4 5 False 2
What this code does
- The accented letter is one character but two bytes in UTF-8.
- Two different character sequences can look the same on screen yet compare as not equal.
This prints True True, then 5 6, then [ Asha] [3.14]. The letter e with an accent is one character but two bytes.
Next step
Check your understanding
12 quick questions