Python – String Methods

July 6, 20264 min readUpdated 8/20/2026

You will handle strings more than any other type. Python gives them about forty methods; this post covers the eight you will actually use, plus the two facts that explain the rest.

Strings never change

Every string method returns a new string. None of them modify the original, because strings are immutable.

name = "  Margherita  "

name.strip()
print(repr(name))          # Output: '  Margherita  '

name = name.strip()
print(repr(name))          # Output: 'Margherita'

The first call did the work and threw it away. You must assign the result. This single mistake accounts for most "the method did nothing" confusion, and it applies to every method below.

repr() is worth knowing here: it shows the quotes and any escape characters, so you can see whitespace that print() hides.

Cleaning input

strip() removes whitespace from both ends — the first thing you do to anything a person typed.

raw = "\n  alice@bank.test  \n"
print(raw.strip())                     # Output: alice@bank.test

print("  left".lstrip() + "|")         # Output: left|
print("file.txt".removesuffix(".txt")) # Output: file

removeprefix() and removesuffix() arrived in 3.9 and are the right tool for chopping a known start or end. Do not use strip(".txt") for that — it removes any of those characters from either end, so "text.txt".strip(".txt") gives you "ex". That is a genuinely surprising bug.

Case

email = "Alice@Bank.TEST"

print(email.lower())                   # Output: alice@bank.test
print("pizza".upper())                 # Output: PIZZA
print("hello world".title())           # Output: Hello World

Normalising with lower() before comparing or storing an email address is standard practice — users do not type consistently and you should not care.

Searching

line = "Deposit: $100.50"

print("Deposit" in line)               # Output: True
print(line.startswith("Deposit"))      # Output: True
print(line.endswith(".50"))            # Output: True
print(line.find("$"))                  # Output: 9
print(line.count("0"))                 # Output: 3

Use in for "is it in there" — it reads better than find() != -1 and is what everyone writes. Reach for find() only when you need the position.

index() does the same as find() but raises ValueError when the substring is absent rather than returning -1. The silent -1 is the more dangerous of the two, because -1 is a valid index.

Splitting and joining

These two are the workhorses. Almost every text-processing job is a split, some work, and a join.

row = "1,alice@bank.test,Alice Cooper"

fields = row.split(",")
print(fields)                          # Output: ['1', 'alice@bank.test', 'Alice Cooper']

print(" | ".join(fields))              # Output: 1 | alice@bank.test | Alice Cooper
print("a b   c".split())               # Output: ['a', 'b', 'c']

split() with no argument splits on any run of whitespace and discards empties, which is what you want for words. split(",") with an argument keeps empty fields, which is what you want for data.

join() reads backwards the first time you see it: the separator is the string you call it on. It only accepts strings, so convert numbers first — ", ".join(str(n) for n in numbers).

For real CSV, use the csv module rather than split(","). A comma inside a quoted field will break your split, and someone's surname will eventually contain one. See Files.

Slicing

Slicing is not a method — it is the indexing syntax, and it works on any sequence.

card = "4111111111111234"

print(card[:4])          # Output: 4111
print(card[-4:])         # Output: 1234
print(card[4:8])         # Output: 1111
print(card[::-1][:4])    # Output: 4321

The rule is [start:stop], where start is included and stop is not. Negative numbers count from the end, so [-4:] is "the last four" — the idiom for masking a card number. A slice never raises for being out of range; it just gives you what is there.

Replacing, and testing what a string contains

replace() swaps every occurrence, and returns a new string like everything else:

amount = "$1,200.50"

cleaned = amount.replace("$", "").replace(",", "")
print(cleaned)                         # Output: 1200.50
print(float(cleaned))                  # Output: 1200.5

Chaining two replace() calls to strip currency formatting before converting is a common and perfectly readable idiom. Pass a third argument to limit how many it replaces.

The is...() family answers "what kind of characters are in here", which is how you validate input without a try/except:

print("12345".isdigit())               # Output: True
print("12.5".isdigit())                # Output: False
print("alice".isalpha())               # Output: True
print("   ".isspace())                 # Output: True
print("".isdigit())                    # Output: False

Two things to notice. "12.5".isdigit() is False — a decimal point is not a digit, so this tests for whole numbers only. And the empty string is False for all of them, which is usually the behaviour you want and occasionally the one that surprises you.

For anything more complicated than these, converting inside a try/except is clearer than assembling a test.

Do not build strings with += in a loop

Because strings are immutable, += in a loop builds a brand new string every iteration and throws the previous one away. On a few items nobody notices. On a hundred thousand it is quadratic.

words = ["Total", "balance", "is", "$9,650.50"]

# Slow, and not how it is written
slow = ""
for word in words:
    slow += word + " "

# What to write instead
fast = " ".join(words)
print(fast)              # Output: Total balance is $9,650.50

join() knows how long the result will be and allocates once. Build a list, join it at the end — the same advice as StringBuilder in Java, with better syntax.

The ones worth memorising

MethodDoes
strip()Trim whitespace from both ends
lower() / upper()Change case, usually to compare
split(sep)String to list
sep.join(items)List to string
replace(old, new)Swap every occurrence
startswith() / endswith()Test an end, cheaply
inTest containment

Everything else you can look up when you need it. Next: f-strings, which is how you assemble strings rather than take them apart.