CodeOath
← All posts
Python70 min total · 18 parts

Python Fundamentals for Interviews: Data Structures, Comprehensions, and Gotchas

Contents — Part 3 of 18: Strings and String Formatting
Part 3 of 18 · ~1 min

Strings and String Formatting

Strings are immutable sequences of characters — every "modification" actually creates a new string object:

s = "hello"
s[0] = "H"        # TypeError: 'str' object does not support item assignment
s = "H" + s[1:]   # "Hello" — a brand new string, `s` now points to it

This immutability is why building a large string by repeated += in a loop is a real performance trap — each += allocates an entirely new string and copies the old contents into it, making an O(n)-per-iteration operation inside an O(n) loop, i.e. O(n²) overall:

# Slow for large n — a new string object allocated on every iteration
result = ""
for word in words:
    result += word + " "

# Fast — str.join builds the final string once
result = " ".join(words)

f-strings vs. .format() vs. %

name, score = "Ana", 97.456

f"{name} scored {score:.1f}"       # "Ana scored 97.5" — preferred in modern code
"{} scored {:.1f}".format(name, score)  # same result, older style
"%s scored %.1f" % (name, score)   # oldest style, still seen in logging calls

f-strings (Python 3.6+) are the current convention — they're evaluated at runtime as real expressions (f"{a + b}" works), not just variable substitution, and are generally the fastest of the three. The %-style is still common specifically in logging calls (logging.info("%s failed", name)) because the string interpolation there is deferred — it only happens if that log level is actually enabled, avoiding the cost of formatting a message nobody will see.

Common string methods worth having memorized

"  hi  ".strip()          # "hi" — also lstrip(), rstrip()
"a,b,,c".split(",")       # ['a', 'b', '', 'c']
",".join(["a", "b", "c"]) # "a,b,c"
"Hello".lower()           # "hello"
"cat" in "concatenate"    # True — substring check
"hello".replace("l", "L") # "heLLo"