PythonBeginner 14 min Lesson 3 of 30

Day 3 — Strings

Work with text in Python: indexing, slicing, the string methods you will actually use, and why strings cannot be changed in place.

Python · Lesson 3 of 30
0/30 done(0%)

What is it? #

A string is a sequence of characters. Every character has a position, starting at 0 for the first one. That numbering trips people up for about a week and then becomes second nature.

Strings are immutable, which means you cannot change one after it is created. name[0] = "R" is an error. Every operation that looks like it edits a string actually builds a new one and hands it back, leaving the original untouched.

Python gives strings a large set of built-in methods — .strip(), .lower(), .split(), .replace() and friends. You do not need a library for ordinary text work.

Because strings are sequences, they also support slicing: asking for a range of positions in one go. Slicing is used constantly, and once you know the pattern it applies to lists too.

Think of it like this #

Think of a string as a row of numbered lockers, each holding one character. You can read any locker by its number, and you can ask for lockers 3 through 7 as a group. What you cannot do is swap the contents of locker 3 — that row is sealed. If you want a different row, you build a new one.

Simple example #

Someone types their email into a form as " [email protected] ". Before you store it you want the spaces gone, everything lowercase, and the part before the @ on its own. That is three method calls and one split.

Code #

PYTHON
raw = "  [email protected]  "

email = raw.strip().lower()
print(email)                 # [email protected]

username, domain = email.split("@")
print(username, "|", domain) # priya.sharma | example.com

# Indexing and slicing
print(email[0])              # p
print(email[-1])             # m   (last character)
print(email[:5])             # priya
print(email[-4:])            # .com

# Useful checks
print(email.endswith(".com"))        # True
print("@" in email)                  # True
print(email.replace(".", "_", 1))    # [email protected]

# Strings are immutable
original = "hello"
shouted = original.upper()
print(original, shouted)     # hello HELLO

How it works #

raw.strip() returns a new string with whitespace removed from both ends, and .lower() returns another new string in lowercase. Chaining them works because each method hands back a string that the next method can act on.

email.split("@") cuts the string wherever it finds @ and returns a list of the pieces. Because an email has exactly one @, the list has two items, and username, domain = ... unpacks them into two names in one line.

email[0] reads position 0. email[-1] counts backwards from the end, so -1 is the last character. Negative indexing saves you from writing len(email) - 1 everywhere.

email[:5] is a slice: start at the beginning, stop before position 5. The end is always exclusive, which is why [:5] gives you exactly five characters. email[-4:] means "from four before the end, to the end".

.endswith() and the in operator return booleans, so they slot straight into an if. .replace(".", "_", 1) replaces only the first occurrence because of the 1.

The last block is the immutability point made concrete: original is unchanged after .upper(), because .upper() built a new string instead of editing the old one.

Real-world use #

Text cleaning is a constant task in real software. Emails get normalised before they are compared, usernames get trimmed so a trailing space does not create a duplicate account, file names get sanitised before they hit disk, and log lines get split on a delimiter to extract a field.

Slicing shows up whenever you need part of an identifier: the first two letters of a country code, the last four digits of a card, the extension at the end of a file name.

The immutability rule has a performance consequence worth knowing early. Building a large string by repeatedly doing text = text + line creates a fresh copy every time. Collect the pieces in a list and call "".join(pieces) once instead — that is the idiom you will see in production code.

Common mistakes #

  • Expecting .strip() to change the original string. It returns a new one — you have to assign the result.
  • Reading s[5] on a shorter string and hitting an IndexError. Slices are forgiving, single indexes are not.
  • Using .strip("abc") and expecting it to remove the word "abc". It removes any of those characters from the ends, in any order.
  • Comparing user text without normalising first. "Priya" == "priya" is False, which is why you lowercase before comparing.
  • Building big strings with += inside a loop. Use a list and "".join().

Practice #

Take the string " 2026-09-22 | ERROR | payment failed for order 8891 ". Strip it, split it on "|", strip each piece, and print the date, the level and the message on separate lines. Then print just the order number using a slice.

Quick quiz

  1. 1. What does `"python"[1:4]` return?

  2. 2. What happens when you call `name.upper()`?

  3. 3. What does `"a,b,c".split(",")` produce?

  4. 4. What is `text[-1]`?

  5. 5. Why is `"".join(parts)` preferred over repeated `+=` in a loop?

Summary

  • Strings are sequences of characters indexed from 0, with negative indexes counting from the end.
  • Slices use `[start:stop]` and the stop position is never included.
  • Strings are immutable — methods return new strings rather than editing in place.
  • `.strip()`, `.lower()`, `.split()`, `.replace()` and `in` cover most everyday text work.
  • Build large strings with `"".join(list_of_parts)` instead of repeated concatenation.