Strings
1.1 Strings
1.1.1 Mental model: what a string really is
A Python string is an immutable sequence of Unicode characters.
Example:
s = "python"
This means two important things.
It is ordered
Each character has a position, or index.
s[0] # 'p'
s[1] # 'y'
It is immutable
You cannot change characters in place.
This will fail:
s[0] = "P"
Error:
TypeError: 'str' object does not support item assignment
This is extremely important.
If you “modify” a string, Python creates a new string object.
Example:
s = "python"
s = s.upper()
The original string is not mutated.
This distinction becomes important later for memory model questions.
1.1.2 Indexing and slicing
This is one of the most frequently tested string topics.
Basic indexing
s = "python"
s[0] # 'p'
s[1] # 'y'
s[-1] # 'n'
s[-2] # 'o'
Negative indices count from the end.
This is a very common Python idiom.
Slicing syntax
General syntax:
s[start:stop:step]
Where:
start= inclusivestop= exclusivestep= jump size
Example:
s = "python"
s[0:3] # 'pyt'
s[:3] # 'pyt'
s[3:] # 'hon'
s[::2] # 'pto'
Important interview trap
The stop index is exclusive.
Example:
s[0:3]
returns:
'pyt'
not 'pyth'.
This is often tested live.
1.1.3 Reversing strings
A classic interview question.
Pythonic way
s = "python"
reversed_s = s[::-1]
Result:
'nohtyp'
This uses slicing with:
step = -1
Very common interview solution.
Alternative: reversed()
''.join(reversed(s))
Important distinction
reversed(s)
returns an iterator, not a string.
So join() is needed.
Interview reasoning
A strong answer should mention:
- slicing is concise and idiomatic
reversed()is explicit- both are
O(n)
Definitions:
- Concise: it expresses the same logic using fewer characters and less code while remaining clear.
- Idiomatic: it follows the style and conventions that experienced Python developers naturally use and expect to see.
- Explicit: it makes the intended action more directly visible in the code, so the reader immediately understands what is happening.
1.1.4 split()
This is extremely important for backend work.
Used constantly in:
- parsing input
- CSV-like data
- API payload cleanup
- tokenization
Basic usage
text = "python interview prep"
words = text.split()
Result:
['python', 'interview', 'prep']
By default it splits on whitespace.
Custom separator
csv = "a,b,c"
parts = csv.split(",")
Result:
['a', 'b', 'c']
Important subtlety
"a b".split()
Result:
['a', 'b']
split() splits on any whitespace and collapses repeated whitespace.
But:
"a b".split(" ")
Result:
['a', '', 'b']
split(" ") splits on exactly one space character and preserves empty fields.
This distinction is interview-worthy.
1.1.5 join()
This is one of the most important string operations.
Basic syntax
" ".join(["python", "interview"])
Result:
'python interview'
Why join() matters
A very common interview question is:
Why use join() instead of repeated +?
Because repeated concatenation creates many temporary strings.
Bad:
result = ""
for word in words:
result += word
Better:
result = "".join(words)
This is more efficient.
1.1.6 strip()
Used constantly in backend input cleaning.
s = " hello "
s.strip()
Result:
'hello'
Variants
s.lstrip()
s.rstrip()
These remove only left or right whitespace.
Custom characters
"---hello---".strip("-")
Result:
'hello'
Important note:
strip() removes characters from the edges only, not inside the string.
1.1.7 replace()
Used for normalization and cleaning.
s = "hello world"
s.replace("world", "python")
Result:
'hello python'
Important note:
replace() returns a new string.
The original string is unchanged.
1.1.8 f-strings
Very important for modern Python.
name = "Ruben"
age = 30
msg = f"My name is {name} and I am {age}"
Result:
'My name is Ruben and I am 30'
This is the preferred modern formatting style.
Expressions inside f-strings
f"{2 + 3}"
Result:
'5'
Formatting
price = 12.3456
f"{price:.2f}"
What :.2f means
:→ start formatting rules.2→ show 2 decimal placesf→ format as fixed-point float
Result:
'12.35'
Very commonly used in production code.
1.1.9 Additional important string methods
These should absolutely be included.
lower() / upper()
s.lower()
s.upper()
Used constantly in normalization.
Realistic backend example:
email = email.strip().lower()
startswith() / endswith()
Common in validation.
filename.endswith(".json")
url.startswith("https")
find()
s.find("py")
Returns the index or -1.
1.1.10 Common interview problems
Strings are often tested through problems like:
- palindrome check
- reverse words
- anagram check
- first unique character
- longest substring
- valid parentheses
So this chapter is foundational.
Verbal interview questions
Answer these out loud:
- Why are strings immutable?
- Why is
join()preferred over repeated+? - Explain why the slicing stop index is exclusive.
- What is the difference between
split()andsplit(" ")? - Why does
replace()not mutate the original string?
Core operations, interview reasoning, and real-world usage
Strings are one of the most tested Python fundamentals because they sit at the intersection of data transformation, parsing, backend development, and algorithmic interview questions.
A surprising number of interview questions are really string problems in disguise.
Examples:
- validate input
- parse logs
- normalize text
- detect patterns
- reverse words
- format output
This chapter is not just about syntax. The goal is to understand how to think about strings as a data structure.
Coding drills
Drill 1: palindrome
def is_palindrome(s: str) -> bool:
...
Drill 2: normalize email
def normalize_email(email: str) -> str:
...
Drill 3: reverse words
def reverse_words(text: str) -> str:
...
Note: what “normalize” means
In programming, normalize means to convert data into a consistent, standard format so it can be processed reliably.
For example:
email = email.strip().lower()
This normalizes email input by removing surrounding whitespace and converting it to lowercase.