You need Python installed, and to know how to run a
.py file. If python3 --version in a
terminal prints a version number, you are ready. If it does not — or
if you have never opened a terminal — do
Getting Started with
Python first; it installs Python and runs your first program, and
takes about fifteen minutes. Nothing else is needed: no account, no
payment, no extra software.
String Basics Recap
Strings are sequences of characters. You already know how to create them and use basic operations like concatenation. Now let's explore Python's powerful built-in string methods that save you from writing custom logic.
text = "Hello, World!"
print(type(text)) # <class 'str'>
print(len(text)) # 13
String methods never modify the original string — they always return a new string. The original stays unchanged unless you reassign the variable.
Case Methods
text = "Hello, World!"
print(text.upper()) # HELLO, WORLD!
print(text.lower()) # hello, world!
print(text.title()) # Hello, World!
print(text.capitalize()) # Hello, world!
print(text.swapcase()) # hELLO, wORLD!
# Useful for case-insensitive comparison
user_input = "YES"
if user_input.lower() == "yes":
print("Confirmed!")
Search and Check Methods
text = "Python is awesome and Python is fun"
# Find position of substring
print(text.find("awesome")) # 10
print(text.find("missing")) # -1 (not found)
print(text.index("awesome")) # 10 (raises ValueError if not found)
# Count occurrences
print(text.count("Python")) # 2
print(text.count("is")) # 2
# Check start/end
filename = "report.pdf"
print(filename.startswith("report")) # True
print(filename.endswith(".pdf")) # True
print(filename.endswith((".pdf", ".doc"))) # True (tuple of suffixes)
Content Check Methods
print("hello123".isalnum()) # True (letters + numbers only)
print("hello".isalpha()) # True (letters only)
print("12345".isdigit()) # True (digits only)
print("hello".islower()) # True (all lowercase)
print("HELLO".isupper()) # True (all uppercase)
print(" ".isspace()) # True (whitespace only)
Modify and Clean Methods
# Strip whitespace (very common for user input)
dirty = " hello world "
print(dirty.strip()) # "hello world"
print(dirty.lstrip()) # "hello world "
print(dirty.rstrip()) # " hello world"
# Strip specific characters
url = "///path/to/page///"
print(url.strip("/")) # "path/to/page"
# Replace substrings
text = "I like cats. Cats are great."
print(text.replace("cats", "dogs")) # I like dogs. Cats are great.
print(text.replace("cats", "dogs", 1)) # Replace only first occurrence
Split and Join
These two methods are among the most useful in Python:
# Split a string into a list
sentence = "Python is a great language"
words = sentence.split() # Split by whitespace (default)
print(words) # ['Python', 'is', 'a', 'great', 'language']
csv_data = "Alice,25,Engineer"
fields = csv_data.split(",") # Split by comma
print(fields) # ['Alice', '25', 'Engineer']
# Limit splits
text = "one:two:three:four"
print(text.split(":", 2)) # ['one', 'two', 'three:four']
# Join a list into a string
words = ["Python", "is", "fun"]
print(" ".join(words)) # "Python is fun"
print("-".join(words)) # "Python-is-fun"
print(", ".join(words)) # "Python, is, fun"
A common pattern is to split a string, process the parts, and join them back.
For example, to capitalize each word: " ".join(word.capitalize() for word in text.split())
String Slicing
text = "Python Programming"
# Syntax: string[start:end:step]
print(text[0:6]) # "Python" (index 0 to 5)
print(text[7:]) # "Programming" (index 7 to end)
print(text[:6]) # "Python" (start to index 5)
print(text[-11:]) # "Programming" (last 11 chars)
print(text[::2]) # "Pto rgamn" (every 2nd char)
print(text[::-1]) # "gnimmargorP nohtyP" (reversed)
Advanced f-String Formatting
f-strings support powerful formatting beyond simple variable insertion:
# Number formatting
price = 49.99
print(f"Price: ${price:.2f}") # Price: $49.99
print(f"Price: ${price:10.2f}") # Price: $49.99 (padded)
big = 1234567
print(f"Count: {big:,}") # Count: 1,234,567
# Percentage
ratio = 0.856
print(f"Score: {ratio:.1%}") # Score: 85.6%
# Padding and alignment
name = "Alice"
print(f"|{name:<10}|") # |Alice | (left-aligned)
print(f"|{name:>10}|") # | Alice| (right-aligned)
print(f"|{name:^10}|") # | Alice | (centered)
print(f"|{name:*^10}|") # |**Alice***| (centered with fill)
# Expressions inside f-strings
x = 10
print(f"{x} squared is {x**2}") # 10 squared is 100
print(f"{'yes' if x > 5 else 'no'}") # yes
Multi-line Strings
# Triple quotes for multi-line
message = """Dear User,
Thank you for signing up.
Your account is now active.
Best regards,
The Team"""
print(message)
# Raw strings (ignore escape characters)
path = r"C:\Users\name\documents"
print(path) # C:\Users\name\documents (no escaping needed)
Practical Examples
# Clean and validate email
def clean_email(email):
email = email.strip().lower()
if "@" in email and "." in email.split("@")[1]:
return email
return None
print(clean_email(" Alice@Example.COM ")) # alice@example.com
print(clean_email("invalid")) # None
# Parse a log line
log = "2026-03-04 10:30:15 ERROR Database connection failed"
parts = log.split(" ", 3) # Split into max 4 parts
date, time, level, msg = parts
print(f"[{level}] {msg} at {date} {time}")
# [ERROR] Database connection failed at 2026-03-04 10:30:15
# Build a simple table
headers = ["Name", "Age", "City"]
rows = [
["Alice", "25", "London"],
["Bob", "30", "Paris"],
["Charlie", "28", "Berlin"]
]
for header in headers:
print(f"{header:<10}", end="")
print()
print("-" * 30)
for row in rows:
for cell in row:
print(f"{cell:<10}", end="")
print()
Now Do It Yourself: Five Steps
The methods above are the toolbox. This is the job: you will take one messy line of user input and turn it into a clean name, a username and an email address. Every result below is what Python actually printed when these lines were run.
Go: open a terminal and type python3, then press Enter. You will see the >>> prompt.
Do: type this line, keeping the two spaces at each end exactly as shown.
raw = " ALICE Johnson "
You should see: nothing at all — assignment is silent. Type raw on its own and press Enter to check: it prints ' ALICE Johnson ', quotes and spaces included. That is real data as it arrives from a web form.
If not: if the spaces have vanished, your terminal or editor trimmed them on paste. Type the line by hand instead — the whole point of the next step is removing those spaces yourself.
Go: stay at the >>> prompt.
Do: run these two lines.
print(repr(raw.strip()))
print(raw.strip().title())
You should see: 'ALICE Johnson' then Alice Johnson. repr() is used on the first so you can see the quotes and confirm the spaces are gone; plain print would show a trimmed-looking string either way.
If not: if raw still has its spaces afterwards, that is correct and is the single most surprising thing about Python strings: they are immutable. raw.strip() does not change raw, it hands back a new string. Run name = "alice", then name.upper(), then name — it still prints alice. You must assign the result to keep it.
Go: same prompt.
Do: run this one line.
print(raw.strip().title().split())
You should see: ['Alice', 'Johnson'] — a list of two strings. Called with no argument, split() breaks on any run of whitespace and quietly discards empty pieces, which is exactly what you want for human-typed input.
If not: if you get ['', '', 'Alice', 'Johnson', '', ''], you called split(" ") with an explicit space. That version treats every single space as a separator and keeps the empty gaps between them. Use bare split() for text a person typed.
Go: same prompt.
Do: run these four lines.
e = "alice.johnson@example.com"
print(e[:e.index("@")])
print(e[e.index("@")+1:])
print(e[-3:])
You should see: alice.johnson, then example.com, then com. Slicing is [start:end], the end is not included, and a negative number counts back from the right — so [-3:] means "the last three characters".
If not: ValueError: substring not found means there is no @ in the string at all. index() raises rather than returning nothing; if the character might be absent, use e.find("@"), which returns -1 instead of raising.
Go: leave the prompt with exit() and create a file called clean.py.
Do: put these five lines in it and run python3 clean.py.
parts = " ALICE Johnson ".strip().title().split()
first, last = parts[0], parts[1]
user = f"{first[0].lower()}{last.lower()}"
print(f"{first} {last} <{user}@example.com>")
print("-".join(["2026", "03", "04"]))
You should see: Alice Johnson <ajohnson@example.com> and then 2026-03-04. The f-string builds text from variables; join is split in reverse, and note it is called on the separator, not on the list.
If not: IndexError: list index out of range means the input had only one word, so parts[1] does not exist. Real input does that constantly — check len(parts) before unpacking. And if join raises TypeError: sequence item 0: expected str instance, int found, your list holds numbers: join only accepts strings.
Without scrolling up: after name = "alice" and name.upper(), what does
name print, and why? If you can answer that, you have understood immutability
— the idea behind almost every "but I changed it!" bug with Python strings.
Answer: alice. Methods return a new string; the original is never
modified. You need name = name.upper().
Now do it without the page: take the messy string
" BOB smith " and produce bsmith@example.com. Same five
moves, different input — if it works first time, the pattern has stuck.
Summary
- Case:
upper(),lower(),title(),capitalize() - Search:
find(),count(),startswith(),endswith(),in - Clean:
strip(),replace() - Split/Join:
split()breaks strings apart,join()combines lists - Slicing:
string[start:end:step]extracts substrings - f-strings: Support number formatting, alignment, padding, and expressions
You can now manipulate text like a pro. Next up: reading and writing files — making your programs work with data stored on disk.