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

Working with Strings

1 · The lesson

read

You will use strings in almost every program you write: for filenames, user input, API responses, log lines and error messages. Python makes text easy to work with, and the dozen methods in this lesson cover most everyday text tasks.


1. Three Ways to Quote

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

Single and double quotes do the same thing. Pick the one that lets you avoid escaping (writing \ before a quote character). 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 the result is not saved anywhere)
print(name)                     # "surya"  (unchanged)

name = name.upper()             # to "update" a string, assign the new one to the name
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 on purpose. Because no code can change a string, many parts of a program can safely use the same string object without copying it.


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'   (the last character)
print(s[-2])                    # 'o'   (the second-to-last character)

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

python
s = "Python rocks"

print(s[0:6])                   # 'Python'         (characters 0 to 5)
print(s[7:])                    # 'rocks'          (from index 7 to the end)
print(s[:6])                    # 'Python'         (from the start, stopping before 6)
print(s[-5:])                   # 'rocks'          (the last 5 characters)

# The step argument
print(s[::2])                   # 'Pto ok'         (every 2nd character)
print(s[::-1])                  # 'skcor nohtyP'   (reversed, the usual Python way)

Slices never raise an IndexError when the bounds are out of range. Python quietly limits them to the length of the string. A single index that is out of range does raise an IndexError.

python
s = "Python"
print(s[100:200])               # ''   (an empty slice, and no error)
print(s[100])                   # IndexError: string index out of range

4. Joining and Repeating

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

+ only works between two strings. If you mix types, Python raises a 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.")  # works, but f-strings (next lesson) do this better

5. The Methods You'll Use Every Day

Each of these returns a new string (or a list, or a bool). The original string does not change.

python
text = "  Hello, World!  "

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

Splitting and joining, the two methods you will use most often:

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

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

# join() does the opposite. It joins a list of strings, with a separator between them
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("alice"))    # True
print(email.endswith(".com"))       # True
print(email.find("@"))              # 5   (index of the first match, or -1 if there is none)
print(email.count("e"))             # 3   (counts matches that do not overlap)

print("@" in email)                 # True   (`in` is the cleanest way to check for a substring)
print("xyz" in email)               # False

find() returns -1 when the substring is absent. There is also .index(), which raises a ValueError instead. Use .find() if you want to check the result with if, and .index() if a missing substring should be an error.


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 escape sequences you will see most often: \n newline, \t tab, \r carriage return, \\ backslash, \" and \' quotes, \0 null byte.


7. Raw Strings

If you put r before a string, 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   (an empty string is still a valid string)
print(len("  spaces  "))        # 10  (spaces count as characters)

len() is a built-in function, not a method. Write len(s), not 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 and debug syntax. For now, just know that f-strings are how you build dynamic strings in modern Python. Use them instead of + 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']        (several spaces in a row count as one)
"a b  c".split(" ")             # ['a', 'b', '', 'c']    (splits at every space, keeps empty strings)

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 each number to a string first)

4. Building long strings with + in a loop.

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

# Fast: join the whole list once, at the end
result = " ".join(words)
+ setup added so this can run · re-runs 1 earlier block on this page first
words = ["alpha", "beta", "gamma"]

# Earlier blocks on this page that this one builds on, re-run quietly first.
_pm_earlier = [
    'csv = "apple,banana,cherry"\nparts = csv.split(",")          # [\'apple\', \'banana\', \'cherry\']\nprint(parts[1])                 # \'banana\'\n\nwords = "the quick brown fox".split()    # with no argument, split on any whitespace\nprint(words)                    # [\'the\', \'quick\', \'brown\', \'fox\']\n\n# join() does the opposite. It joins a list of strings, with a separator between them\nprint("-".join(["2026", "05", "14"]))    # \'2026-05-14\'\nprint(", ".join(words))                  # \'the, quick, brown, fox\'',
]
def _pm_run_earlier(_srcs, _g):
    import sys as _s, io as _io, warnings as _w
    for _src in _srcs:
        _o, _e = _s.stdout, _s.stderr
        _s.stdout = _s.stderr = _io.StringIO()
        try:
            with _w.catch_warnings():
                _w.simplefilter('ignore')
                exec(compile(_src, '<earlier block>', 'exec'), _g)
        except (Exception, SystemExit):
            pass
        finally:
            _s.stdout, _s.stderr = _o, _e
    if 'matplotlib.pyplot' in _s.modules:
        _s.modules['matplotlib.pyplot'].close('all')   # their plots belong to their own blocks
_pm_run_earlier(_pm_earlier, globals())
del _pm_earlier, _pm_run_earlier

With a few hundred items, you won't notice the difference. With a very large number of items, the join() version can be much faster.


🎯 Your Turn: Build a Slugifier

Write a short program that turns a title into a slug, a short version that is safe to use in a URL:

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

Rules:
1. Lowercase everything.
2. Replace the punctuation characters , ! ' and - with spaces.
3. Split the text into words, and join the words with -.

Step 3 also removes extra spaces, because .split() with no argument ignores spaces at both ends and treats several spaces in a row as one.

Skeleton:

python
title = "Hello, World! 2026"

# TODO 1: make the title lowercase
# TODO 2: replace "," "!" "'" and "-" with spaces
# TODO 3: split into words, then join the words with "-"
slug = ...

print(slug)    # expect: hello-world-2026

When it works, change title to " Python Rocks " (expect python-rocks) and to "It's --- awesome!" (expect it-s-awesome), and run it again.

Hint 1: Calling one method after another Each string method returns a new string, so you can call the next method on the result: title.lower().replace(",", " ").replace("!", " "). To replace the ' character, put it inside double quotes: .replace("'", " ").
Hint 2: Split, then join " it s awesome ".split() gives ['it', 's', 'awesome']. Then "-".join(words) puts one - between the words, and none at the ends.
Show full solution
python
title = "Hello, World! 2026"

cleaned = title.lower()
cleaned = cleaned.replace(",", " ").replace("!", " ").replace("'", " ").replace("-", " ")
words = cleaned.split()
slug = "-".join(words)

print(words)    # ['hello', 'world', '2026']
print(slug)     # hello-world-2026

With title = "It's --- awesome!", words is ['it', 's', 'awesome'] and the slug is it-s-awesome.

This version handles only the punctuation characters you list. A title with ? or : needs another .replace() call. A production version would use the re module: re.sub(r"[^a-z0-9]+", "-", text.lower()).strip("-") replaces every run of characters that are not a lowercase letter or a digit, in one line. The code is shorter, but harder to read.


What You Learned

  • Three quote styles: single, double and triple. Pick the one that avoids 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 methods you will use most: .upper(), .lower(), .strip(), .split(), .join(), .replace(), .startswith(), .endswith(), .find(), .count().
  • in is the simplest way to check for a substring.
  • r"..." makes a raw string, useful for Windows paths and regex.
  • len(s) for length. Never s.len().

Next: F-Strings, the modern way to build strings from values, with format specifiers that make numbers and alignment easy.

Practice this

on practicepython.in

Short exercises that run in your browser and tell you what your code did, as well as whether a test passed.

Found this useful? Share it with a friend who’s learning Python.