🐍 Python Course

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 = inclusive
  • stop = exclusive
  • step = 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 places
  • f → 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:

  1. Why are strings immutable?
  2. Why is join() preferred over repeated +?
  3. Explain why the slicing stop index is exclusive.
  4. What is the difference between split() and split(" ")?
  5. 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.