Python’s string model
A Python str is an immutable sequence of Unicode code points. An interview question may instead mean ASCII letters, bytes, or visible symbols. Establish that contract before you choose a data structure. This course uses code points unless a problem says otherwise.
Distinguish characters, code points, and immutable strings before solving a problem.
Start with the contract
Ask what empty input means, whether case matters, and whether spaces count. “Is this a palindrome?” has different answers under exact comparison and punctuation-free comparison. Do not normalize unless the specification asks you to.
message = "café"
assert len(message) == 4
assert message[0] == "c"
assert message[-1] == "é"
assert "A" != "a"
assert len("e\u0301") == 2
The final example is an e followed by a combining accent: two code points that can look like one letter. Reversing such a string reverses code points, not user-perceived characters.
Immutability changes your approach
You cannot assign to message[0]. Build a new value instead. A loop that inspects characters can use constant auxiliary space; a transformation that returns a new string needs storage for that output. Say which space measure you mean.
Guided practice
Count exact occurrences of a target character. Maintain an integer counter; after visiting the first i characters, the counter must equal the matches in that prefix. This sentence is your first loop invariant.
Check your understanding
Does empty input contain zero characters? Yes. Should A match a under exact equality? No. Can two visually similar strings differ? Yes: normalization is a separate choice.
Independent practice
Try Count a symbol and Equal-length difference count. Explain the input contract aloud before coding.
Takeaway
Choose semantics first, then a representation. Most subtle string bugs begin with an unstated assumption.
Deeper check: Code points, bytes, and display
Python length counts code points, not encoded bytes or visible graphemes. This matters when an interview statement casually says “characters.” Ask which model it intends before normalizing or reversing. The empty string is a real value, distinct from a missing result such as None. A function that returns an index should state which string that index refers to, especially when a transformation changes length.
text = "é🙂"
assert len(text) == 2
assert len(text.encode("utf-8")) == 6
assert "e\u0301" != "é"
assert "" != None
Apply the idea
Explain why reversing e followed by a combining accent can change its appearance. The reversed code-point order places the accent before the base letter; code-point reversal is not grapheme reversal. Continue to the Unicode lesson for an explicit comparison policy.