String Methods
So far you can create strings (Lesson 1) and pull out individual characters (Lesson 2). But what if you need to change a string to all uppercase? Or remove extra spaces? Or split "python,ai,beginner" into three separate pieces?
Python gives every string a set of built-in tools called methods. A method is an action you perform on a string by writing a dot after it, followed by the method name and parentheses:
title: str = "hello"
title.upper() # "HELLO"
The dot says "use this method on this string." The parentheses say "do it now." This lesson covers the methods you will use most often.
James has a problem. SmartNotes users sometimes paste titles with extra spaces:
title: str = " My First Note "
He wants to get rid of those leading and trailing spaces. Emma shows him a method called .strip():
title: str = " My First Note "
cleaned: str = title.strip()
print(cleaned) # "My First Note" — spaces gone
print(title) # " My First Note " — still has spaces!
Wait. Why does title still have spaces? Because .strip() did not change title. It created a new string without the spaces and returned it. The original string is untouched. This is called immutability, and it applies to every string method in Python. We will come back to this in detail later in the lesson.
The Core Methods
Each method below does one specific job. Remember the pattern from the intro: write the string, then a dot, then the method name with parentheses.
.strip() — Remove extra spaces from both ends
title: str = " My First Note "
print(title.strip())
Output:
My First Note
.strip() removes spaces (and other invisible characters like tabs) from the beginning and end of the string. Spaces in the middle are not touched.
.upper() — Convert every letter to uppercase
title: str = "My First Note"
print(title.upper())
Output:
MY FIRST NOTE
Every lowercase letter becomes uppercase. Numbers, spaces, and punctuation stay the same.
.lower() — Convert every letter to lowercase
title: str = "My First Note"
print(title.lower())
Output:
my first note
The opposite of .upper(). Useful when you want to compare two strings without caring about capitalization: "Hello".lower() == "hello".lower() is True.
Quick reference
| Method | What It Does | Example | Result |
|---|---|---|---|
.strip() | Remove spaces from both ends | " hi ".strip() | "hi" |
.upper() | Every letter to uppercase | "hi".upper() | "HI" |
.lower() | Every letter to lowercase | "HI".lower() | "hi" |
Searching and Replacing
.replace(old, new) — Swap text inside a string
Give it two arguments: the text to find, and the text to put in its place. It replaces every occurrence:
title: str = "My First Note"
print(title.replace("First", "Second"))
Output:
My Second Note
If the text appears more than once, all occurrences are replaced:
message: str = "yes yes yes"
print(message.replace("yes", "no"))
Output:
no no no
Like all string methods, .replace() returns a new string. The original is unchanged.
.find(text) — Locate where text appears
.find() searches the string and returns the position (index) where the text first appears:
title: str = "My First Note"
print(title.find("First"))
Output:
3
"First" starts at position 3 (remember, counting starts at 0: M is 0, y is 1, the space is 2, F is 3).
What if the text is not there? .find() returns -1 instead of crashing with an error:
title: str = "My First Note"
print(title.find("Missing"))
Output:
-1
A result of -1 means "not found." Any result of 0 or higher means "found at this position."
.startswith(prefix) — Check how a string begins
Returns True if the string starts with the given text, False otherwise:
title: str = "My First Note"
print(title.startswith("My"))
print(title.startswith("Your"))
Output:
True
False
Useful for filtering: "does this note title start with a specific word?"
Quick reference
| Method | What It Does | Returns |
|---|---|---|
.replace(old, new) | Swap every old with new | New string with replacements |
.find(text) | Find position of first match | Index (int), or -1 if not found |
.startswith(prefix) | Check if string begins with prefix | True or False |
Splitting and Joining
.split() — Break a string into a list of pieces
Sometimes you have one string that contains multiple values. .split() chops it into separate pieces and gives you a list (a collection you will learn fully in Lesson 4).
With no argument, .split() splits on spaces:
sentence: str = "hello world python"
words: list[str] = sentence.split()
print(words)
Output:
['hello', 'world', 'python']
One string became three separate strings inside a list.
You can tell .split() what character to split on by passing it as an argument. For example, split on commas:
csv_line: str = "python,ai,beginner"
tags: list[str] = csv_line.split(",")
print(tags)
Output:
['python', 'ai', 'beginner']
The comma is the separator: .split(",") means "cut wherever you see a comma." The commas themselves are removed from the results.
"separator".join(list) — Combine a list back into one string
.join() is the opposite of .split(). It takes a list of strings and glues them together with a separator between each one.
The syntax looks unusual: you call .join() on the separator string, and pass the list inside the parentheses:
words: list[str] = ["hello", "world"]
sentence: str = " ".join(words)
print(sentence)
Output:
hello world
" ".join(words) means "take every item in words and put a space between them."
Change the separator to get different results:
tags: list[str] = ["python", "ai", "beginner"]
print(", ".join(tags)) # comma + space between each
print(" - ".join(tags)) # dash between each
print("".join(tags)) # nothing between each
Output:
python, ai, beginner
python - ai - beginner
pythonaibeginner
Quick reference
| Method | What It Does | Example | Result |
|---|---|---|---|
.split() | Split on spaces | "a b c".split() | ["a", "b", "c"] |
.split(",") | Split on a specific character | "a,b,c".split(",") | ["a", "b", "c"] |
" ".join(list) | Join list with spaces | " ".join(["a", "b"]) | "a b" |
", ".join(list) | Join list with comma + space | ", ".join(["a", "b"]) | "a, b" |
The ", ".join(tags) pattern is exactly what the SmartNotes format_tag_list() function will use in the TDG (Test-Driven Generation) Challenge at the end of this chapter. TDG is the workflow you learned in Chapter 46: write a specification with types and tests, let AI generate the implementation, then verify. You are learning the building block now; you will apply it as a specification later.
Immutability: The Key Rule
This is the most important concept in this lesson. Every beginner hits this confusion at least once, so read carefully.
Strings in Python are immutable. That means once a string is created, it can never be changed. Not by you, not by any method, not by anything.
So what do string methods do? They create a brand new string and give it back to you. The original stays exactly as it was.
Watch what happens step by step:
title: str = " My First Note "
cleaned: str = title.strip()
print(title) # what is in title?
print(cleaned) # what is in cleaned?
Output:
My First Note
My First Note
title still has the spaces. It was never changed. .strip() built a new string without spaces and we stored it in cleaned.
The common mistake
This code looks like it should work, but it does nothing useful:
title: str = " My First Note "
title.strip() # creates a new string... but nobody saves it!
print(title) # still has spaces
Output:
My First Note
.strip() did its job and produced "My First Note", but since nobody saved the result, it was immediately thrown away. The same mistake applies to every string method: .upper(), .lower(), .replace(), all of them.
The fix: reassign the variable
If you want the variable itself to hold the new value, assign the result back:
title: str = " My First Note "
title = title.strip() # save the result back into title
print(title)
Output:
My First Note
Now title points to the new string. The old " My First Note " still exists in memory briefly, but since nothing points to it anymore, Python cleans it up automatically.
Why this matters for AI-generated code
When you read AI-generated code, look for this pattern. If you see a bare method call with no = assignment:
# Bug: result is thrown away
user_input.strip()
user_input.lower()
That is almost always a mistake. The fix:
# Correct: save each result
user_input = user_input.strip()
user_input = user_input.lower()
Or chain them in one line:
user_input: str = " Hello World "
user_input = user_input.strip().lower()
print(user_input)
Output:
hello world
Chaining works because each method returns a new string, and the next method is called on that new string. .strip() produces "Hello World", then .lower() is called on that result and produces "hello world".
PRIMM-AI+ Practice: Predicting Method Results
Predict [AI-FREE]
Press Shift+Tab to enter Plan Mode before predicting.
Look at these string method calls. Without running anything, predict the exact result of each one. Write your predictions and a confidence score from 1 to 5 before checking.
text: str = " Hello, World! "
# 0123456789...
# ^^ ← two spaces before "Hello"
result1: str = text.strip()
result2: str = text.upper()
result3: str = text.replace("World", "Python")
result4: int = text.find("World")
result5: list[str] = "one two three".split()
Check your predictions
result1: "Hello, World!". .strip() removes the leading and trailing spaces. The space between "Hello," and "World!" is in the middle, so it stays.
result2: " HELLO, WORLD! ". .upper() converts letters to uppercase. But it does NOT remove spaces. The two leading and two trailing spaces are still there. Remember, each method does only one job.
result3: " Hello, Python! ". .replace() swaps "World" for "Python". The spaces around the string are untouched because .replace() only replaces the text you asked for.
result4: 9. This one is tricky. Let's count character positions:
Position: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Character: ' '' ' H e l l o , ' ' W o r l d ! ' ' ' '
^
"World" starts here at position 9
The two leading spaces push everything forward. Without them, "World" would be at position 7.
result5: ["one", "two", "three"]. .split() with no argument splits on spaces.
Run
Press Shift+Tab to exit Plan Mode.
Create a file called method_practice.py with the five expressions above. Add print() calls for each one. Run it with uv run python method_practice.py. Compare the output to your predictions.
Investigate
Look at your result for result4. If you predicted 7 instead of 9, write one sentence explaining what you missed. (The answer: leading spaces are characters too, and they shift every position forward.)
If you want to go deeper, run /investigate @method_practice.py in Claude Code and ask why .find() returns 9 instead of 7 for "World" in the original string.
Modify
Add text = text.strip() as the first line after the string is created. Now predict result4 again. Did the position of "World" change? Run your modified file to check.
Make [Mastery Gate]
Given a messy title string:
raw_title: str = " my FIRST note "
Use the methods from this lesson to produce "my first note" (stripped and lowercase). Write the code yourself without looking at examples. You need two methods.
Then try: can you produce "MY FIRST NOTE" from the same starting string? What about just "my first note" with no extra spaces?
Run uv run python on your file to verify each result.
Try With AI
If Claude Code is not already running, open your terminal, navigate to your SmartNotes project folder, and type claude. If you need a refresher, Chapter 44 covers the setup.
Prompt 1: Test Your Immutability Understanding
I'm learning Python string methods. Here is my code:
title = " Hello "
title.strip()
print(title)
I expect this to print "Hello" without spaces. Is that
correct? If not, explain what I'm getting wrong.
Read AI's response. Did it explain that .strip() returns a new string and the original title is unchanged? Did it suggest title = title.strip() as the fix? Compare its answer to what you learned about immutability.
What you're learning: You are testing a common misconception (that methods change the original string) and seeing how AI explains the fix. This is the same pattern you will use when debugging your own code.
Prompt 2: Generate a String Cleaning Function
Write a Python function called clean_title that takes a
messy title string (with extra spaces and inconsistent
capitalization) and returns a clean version. Use type
annotations. Show 3 example inputs and outputs as comments.
Read AI's output. Check: does it use .strip() to remove whitespace? Does it handle capitalization? Are the type annotations correct? Does it chain methods or use separate steps? If the approach differs from what you learned, ask AI to explain its choice.
What you're learning: You are reviewing AI-generated code that uses the string methods from this lesson. Evaluating whether AI chose the right methods builds your judgment for larger code reviews.
James stares at his screen. "I almost made the immutability mistake. I wrote title.strip() and wondered why the spaces were still there."
"Everyone does it once," Emma says. "The rule is simple: methods return new strings. Save the result or lose it."
"And .split() gives me a list," James adds. "But I do not actually know what a list is yet. I just know it looks like ['python', 'ai', 'beginner']."
Emma nods. "That is exactly where Lesson 4 picks up. You have been working with single values: one string, one number. Now you need variables that hold many values at once. Lists, dicts, tuples, sets. Four collection types, each with a typed annotation."