I have seen this bug in production code written by developers with three or more years of experience.
name = " hello world "
name.strip()
name.upper()
print(name)
What does this print?
Not "HELLO WORLD". Not "hello world". It prints " hello world " exactly as it started.
Both operations were thrown away.
Why String Methods Never Modify In Place
Strings in Python are immutable. Once a string object exists, it cannot be changed. Every string method that appears to modify a string is actually returning a brand new string object.
The operation ran. The result was computed. But you did not capture it anywhere, so it was immediately garbage collected.
The Correct Pattern
name = " hello world "
name = name.strip()
name = name.upper()
print(name)
Output: HELLO WORLD
Or in one line using method chaining:
name = " hello world ".strip().upper()
print(name)
Each method returns a new string. The next method in the chain is called on that new string. The original string is never involved after the first call.
Tracing Method Chaining
result = " Python is Great ".strip().lower().replace("is", "was").split()
print(result)
Trace each step:
Step 1: " Python is Great ".strip() returns "Python is Great"
Step 2: "Python is Great".lower() returns "python is great"
Step 3: "python is great".replace("is", "was") returns "python was great"
Step 4: "python was great".split() returns ["python", "was", "great"]
Output: ['python', 'was', 'great']
The original string " Python is Great " is untouched throughout. Four new string objects were created and three were immediately discarded.
The Interview Problem
def process(text):
text.strip()
text = text.lower()
text.replace(" ", "_")
return text
result = process(" Hello World ")
print(result)
Output: " hello world "
Line by line:
-
text.strip()runs but the result is discarded.textis still" Hello World ". -
text = text.lower()runs and the result IS captured.textis now" hello world ". -
text.replace(" ", "_")runs but the result is discarded.textis still" hello world ". - The function returns
" hello world ". The strip was wasted and the replace was wasted. Only the lower() result was kept because only that line used assignment to capture the return value.
Five Methods That Beginners Forget Return New Strings
s = "hello"
s.upper() # returns "HELLO" -- s unchanged
s.replace("h", "H") # returns "Hello" -- s unchanged
s.strip() # returns "hello" -- s unchanged (no whitespace)
s.center(11) # returns " hello " -- s unchanged
s.encode() # returns b"hello" -- s unchanged
print(s) # still "hello"
Compare to list methods that modify in place:
lst = [3, 1, 2]
lst.sort() # modifies lst in place, returns None
lst.append(4) # modifies lst in place, returns None
print(lst) # [1, 2, 3, 4]
Lists are mutable so their methods modify in place. Strings are immutable so their methods return new objects. This asymmetry is the root of most string-related bugs.
Practice output prediction problems at PyCodeIt.
Top comments (0)