PythonMastery
beginner 15 min read · lesson 7 of 19 in Python Fundamentals

Working with Strings

1 · The lesson

read

Strings are the type you'll touch in every program you write — filenames, user input, API responses, log lines, error messages. Python's string handling is one of the cleanest in any language, and the dozen methods in this lesson cover roughly 90% of real-world text work.


1. Three Ways to Quote

python
single = 'Alice'
double = "Alice"
triple = """Alice
spans multiple lines."""

Single and double quotes are interchangeable — pick whichever avoids escaping. Use double when the string contains an apostrophe, single when it contains a quotation mark:

python
print("It's fine.")             # no need to escape the apostrophe
print('She said "hi".')         # no need to escape the quotes

Triple quotes ("""...""" or '''...''') preserve line breaks and are how you write multi-line strings and docstrings.

python
message = """Dear Alice,

Welcome aboard.
— The Team"""
print(message)

2. Strings Are Immutable

You can't change a string in place. Every "modification" returns a brand new string.

python
name = "surya"
name.upper()                    # returns "SURYA" — but we threw it away
print(name)                     # "surya" — unchanged

name = name.upper()             # reassignment is how you "update"
print(name)                     # "SURYA"

Try to mutate one and Python refuses:

python
s = "hello"
s[0] = "H"                      # TypeError: 'str' object does not support item assignment

This is by design — strings are cheap to share around your program precisely because nobody can modify them behind your back.


3. Indexing and Slicing

Each character has a position, starting at 0. Negative indices count from the end.

python
s = "Python"
print(s[0])                     # 'P'
print(s[3])                     # 'h'
print(s[-1])                    # 'n'   — last character
print(s[-2])                    # 'o'   — second-to-last

Slicing pulls out a range with s[start:stop:step]. stop is exclusive.

python
s = "Python rocks"

print(s[0:6])                   # 'Python'         — characters 0,1,2,3,4,5
print(s[7:])                    # 'rocks'          — from 7 to end
print(s[:6])                    # 'Python'         — from start to 6
print(s[-5:])                   # 'rocks'          — last 5 chars

# The step argument
print(s[::2])                   # 'Pto ok'         — every 2nd character
print(s[::-1])                  # 'skcor nohtyP'   — reversed (idiomatic)

Slices never raise an IndexError for out-of-range bounds — they silently clamp. Bare indices do raise.

python
print(s[100:200])               # ''   — empty slice, no error
print(s[100])                   # IndexError: string index out of range
+ setup added so this can run · defines s
s = ["alpha", "beta", "gamma"]

4. Joining and Repeating

python
greeting = "Hi, " + "Alice"     # 'Hi, Alice'
line = "-" * 30                 # '------------------------------'
shout = "ha" * 5                # 'hahahahaha'

+ only works between two strings. Mixing types throws TypeError:

python
age = 30
print("I am " + age + " years old.")    # TypeError: can only concatenate str (not "int") to str
print("I am " + str(age) + " years old.")  # OK — but f-strings (next lesson) do this better

5. The Methods You'll Use Daily

Each of these returns a new string (or a list, or a bool) — the original is untouched.

python
text = "  Hello, World!  "

print(text.upper())             # '  HELLO, WORLD!  '
print(text.lower())             # '  hello, world!  '
print(text.strip())             # 'Hello, World!'   — trims whitespace both ends
print(text.replace("World", "Alice"))  # '  Hello, Alice!  '

Splitting and joining — the two methods you'll reach for most often:

python
csv = "apple,banana,cherry"
parts = csv.split(",")          # ['apple', 'banana', 'cherry']
print(parts[1])                 # 'banana'

words = "the quick brown fox".split()    # no arg → split on any whitespace
print(words)                    # ['the', 'quick', 'brown', 'fox']

# join() is the inverse — glue an iterable of strings with a separator
print("-".join(["2026", "05", "14"]))    # '2026-05-14'
print(", ".join(words))                  # 'the, quick, brown, fox'

Searching and checking:

python
email = "alice@example.com"

print(email.startswith("surya"))    # True
print(email.endswith(".com"))       # True
print(email.find("@"))              # 5   — index of first match, -1 if missing
print(email.count("e"))             # 2   — non-overlapping occurrences

print("@" in email)                 # True   — `in` is the cleanest substring check
print("xyz" in email)               # False

find() returns -1 when the substring is absent. There's also .index() which raises ValueError instead — use whichever fits your control flow.


6. Escape Sequences

Inside a normal string, \ introduces a special character.

python
print("Line one\nLine two")     # \n is a newline
print("Name:\tAlice")           # \t is a tab
print("She said \"go\".")       # escape the quote that matches the outer quote
print("C:\\Users\\Alice")       # escape the backslash itself

The full set you'll see in the wild: \n newline, \t tab, \r carriage return, \\ backslash, \" and \' quotes, \0 null byte.


7. Raw Strings

Prefix a string with r and backslashes lose their special meaning. This matters most for Windows paths and regular expressions.

python
path = r"C:\Users\Alice\Documents"
print(path)                     # C:\Users\Alice\Documents

# Without the r, you'd need to double every backslash:
path = "C:\\Users\\Alice\\Documents"

In regex patterns (covered later), raw strings keep \d, \w, \b readable:

python
import re
pattern = r"\d{4}-\d{2}-\d{2}"      # matches dates like 2026-05-14
print(re.findall(pattern, "Today is 2026-05-14."))   # ['2026-05-14']

8. Length

python
print(len("Python"))            # 6
print(len(""))                  # 0   — empty string is valid
print(len("  spaces  "))        # 10  — whitespace counts

len() is a built-in function, not a method — len(s), never s.len().


9. F-Strings Are Coming

You've seen f"Hi, {name}" in earlier lessons. The next lesson — F-Strings — covers them in depth: format specifiers, alignment, debug syntax. For now, just know that f-strings are how you build dynamic strings in modern Python. Skip + concatenation when you can.


Common Mistakes

1. Trying to mutate a string.

python
s = "hello"
s[0] = "H"                      # TypeError — strings are immutable
s = "H" + s[1:]                 # correct: build a new string

2. Confusing .split() with no args vs .split(",").

python
"a b  c".split()                # ['a', 'b', 'c']        — any whitespace, collapses runs
"a b  c".split(" ")             # ['a', 'b', '', 'c']    — exactly one space, keeps empties

Use bare .split() for human-typed text. Use .split(",") (or another explicit delimiter) for structured data like CSV.

3. Passing non-strings to .join().

python
",".join([1, 2, 3])             # TypeError: sequence item 0: expected str instance, int found
",".join(str(n) for n in [1, 2, 3])    # '1,2,3'   — convert first

4. Building long strings with + in a loop.

python
# Slow — each += allocates a new string
result = ""
for word in words:
    result += word + " "

# Fast — build a list, join once at the end
result = " ".join(words)
+ setup added so this can run · defines words
words = ["alpha", "beta", "gamma"]

On a few hundred items the difference is invisible; on a million it's the difference between snappy and minutes.


🎯 Your Turn — Build a Slugifier

Write a function slugify(text) that turns a human title into a URL-safe slug:

python
"Hello, World! 2026"    →   "hello-world-2026"
"  Python   Rocks  "    →   "python-rocks"
"It's --- awesome!"     →   "it-s-awesome"

Rules:
1. Lowercase everything.
2. Replace any character that isn't a letter or digit with -.
3. Collapse consecutive - into a single -.
4. Strip leading and trailing -.

Skeleton:

python
def slugify(text):
    # TODO 1: lowercase
    # TODO 2: replace non-alphanumeric chars with '-'
    # TODO 3: collapse runs of '-'
    # TODO 4: strip leading/trailing '-'
    return ...

print(slugify("Hello, World! 2026"))    # expect: 'hello-world-2026'
print(slugify("  Python   Rocks  "))    # expect: 'python-rocks'
Hint 1 — Checking if a character is alphanumeric Strings have an .isalnum() method that returns True for letters and digits. You can build the result one character at a time:
cleaned = "".join(c if c.isalnum() else "-" for c in text.lower())
That's a generator expression inside "".join() — a very Pythonic pattern.
Hint 2 — Collapsing repeated dashes After step 2 you'll have strings like "hello--world----2026". The dumb-but-effective trick: keep replacing "--" with "-" in a while loop until no more changes happen. Then call .strip("-") to remove leading/trailing dashes.
Show full solution
python
def slugify(text):
    # Lowercase, then replace non-alphanumeric with '-'
    cleaned = "".join(c if c.isalnum() else "-" for c in text.lower())

    # Collapse consecutive dashes
    while "--" in cleaned:
        cleaned = cleaned.replace("--", "-")

    # Trim dashes from both ends
    return cleaned.strip("-")


print(slugify("Hello, World! 2026"))    # 'hello-world-2026'
print(slugify("  Python   Rocks  "))    # 'python-rocks'
print(slugify("It's --- awesome!"))     # 'it-s-awesome'
print(slugify("---"))                   # ''

Three lines of real logic. The c if c.isalnum() else "-" ternary inside the generator expression is the heart of it — you'll see that pattern in real codebases for any "transform each character" job.

A production version would use the re module: re.sub(r"[^a-z0-9]+", "-", text.lower()).strip("-") does the whole thing in one line. Same idea, denser syntax.


What You Learned

  • Three quote styles — single, double, triple — pick to avoid escaping.
  • Strings are immutable. Every method returns a new string.
  • Slicing s[start:stop:step] with negative indices and step. s[::-1] reverses.
  • The 10 daily methods: .upper(), .lower(), .strip(), .split(), .join(), .replace(), .startswith(), .endswith(), .find(), .count().
  • in is the cleanest substring test.
  • r"..." for raw strings — paths and regex.
  • len(s) for length. Never s.len().

Next: F-Strings — the modern way to build dynamic strings, with format specifiers that make numbers and alignment trivial.

Practice this

on practicepython.in

Short exercises that run in your browser and tell you what your code actually did, not just whether a test passed.