Session 11 - Strings Toolkit

Session 11 of the Python Fundamentals series, covered in depth. It cleans and shapes text so that messy user input behaves, covering .lower() and .upper(), .strip(), the in keyword for substrings, .startswith() and .endswith(), length, indexing and slicing, .split() and .replace(), and f-strings with formatting. It builds the robust clean-then-compare pattern and a word-count text analyzer, and covers the key traps: strings are immutable, string methods return a new string, .strip() trims only the ends, and comparisons are case-sensitive. Every snippet and error message was copied verbatim from CPython 3.12.

Subject: Python Fundamentals · 95 slides · code lesson

Open the interactive version of this deck · Homework for this lesson

What this lesson covers

The lesson, slide by slide

1. Strings Toolkit

Title

Python Fundamentals - Session 11

Clean and shape text so messy input behaves

2. What you will be able to do

Objectives

input() gives strings, and real users type inconsistently. This session is the toolkit for handling that. By the end you can:

  1. Normalize text with .lower(), .upper(), and .strip().
  2. Search inside text with in, .startswith(), and .endswith().
  3. Measure, index, and slice strings.
  1. Break text apart with .split() and swap parts with .replace().
  2. Build clean output with f-strings.
  3. Handle the immutability and case-sensitivity traps.

3. What survived from Session 10 - Functions, Deeper (Scope & Design)?

Warm-up

Discussion prompt

Before we open Session 11 - Strings Toolkit: without looking back, what was the main idea of Session 10 - Functions, Deeper (Scope & Design), and what could you do by the end of it that you could not do before?

Hint: One sentence for the idea, one for the skill. If the second one is blank, that is the part to revisit.

Answer:

That session covers local scope, shadowing, one-job functions, composition, returning multiple values, a menu program, and the difference between changing a value in place and rebinding it.

4. Messy Text, Clean Code

Section

Part 1

5. Users type inconsistently

Concept

One user types yes, another YES, another Yes . All mean the same thing - but to Python they are three different strings.

Your job is to normalize the text so all of these count as the same answer.

6. Break it if you can: Users type inconsistently

Counterexample

Discussion prompt

One user types yes, another YES, another Yes . All mean the same thing - but to Python they are three different strings.

That is stated as though it always holds. Do one of two things: produce a case where it fails, or say precisely what rules such a case out. "It just does" is not on the menu.

Hint: Hunt at the extremes first — zero, one, negative, empty, equal. If every extreme survives, the reason they survive is the proof.

Answer:

Your job is to normalize the text so all of these count as the same answer.

7. Be forgiving of the user

Intuition

Good programs meet people where they are. Rather than demand perfect input, clean it up: trim the spaces, even out the case, then compare.

A few string methods turn brittle checks into forgiving ones.

8. By analogy: Be forgiving of the user

Analogy

Discussion prompt

Explain Be forgiving of the user by analogy to something with no Python Fundamentals in it at all — a queue, a recipe, a map, a bank balance, whatever fits. Then say where your analogy breaks.

Hint: An analogy that never breaks is not an analogy, it is the same idea wearing a hat. Find the seam — that is the part that is actually new.

Answer:

Good programs meet people where they are. Rather than demand perfect input, clean it up: trim the spaces, even out the case, then compare.

9. A string is a sequence of characters

Concept

"Hello" is really the ordered characters H, e, l, l, o. You can measure it, index into it, and slice pieces out.

That is why many list ideas - len, indexing from 0, in - work on strings too.

10. Teach it back: A string is a sequence of characters

Explain it

Discussion prompt

Explain A string is a sequence of characters to a student a year behind you. No notation, no jargon they have not met — and it still has to be true.

Hint: If your explanation needs a symbol they have never seen, you are describing the notation rather than the idea.

Answer:

"Hello" is really the ordered characters H, e, l, l, o. You can measure it, index into it, and slice pieces out.

11. Changing Case

Section

Part 2

12. .lower() and .upper()

Concept

text.lower() gives an all-lowercase copy; text.upper() an all-uppercase one. Attach the method with a dot.

13. What rests on this: .lower() and .upper()

Socratic

Discussion prompt

text.lower() gives an all-lowercase copy; text.upper() an all-uppercase one. Attach the method with a dot.

Suppose that were not true. What is the first thing in Session 11 - Strings Toolkit that would stop working?

Hint: Follow it one step downstream. The answer is whatever was quietly relying on it.

14. Evening out the case

Worked example

print("HELLO".lower())
print("hi".upper())

Each method returns a new-cased copy

Why: lower makes hello; upper makes HI.

Read the output

Why: Verified by execution.

expressionvalue
"HELLO".lower()hello
"hi".upper()HI

15. Fill in: value for Evening out the case

Comparison

Comparison matrix

From Evening out the case: refill the value column from what you know. The rest of the table is as it appeared.

expressionvalue
"HELLO".lower()hello
"hi".upper()HI

16. Methods return a new string

Concept

String methods do not change the original - they hand back a new string. Strings themselves never change (more on that soon).

So you must use or store the result: text = text.lower().

17. Restore the missing line: The original is unchanged

Fill the middle

Fill in the blanks

From The original is unchanged — one line has had its right-hand side removed. Put it back.

word = "Hello"
word.lower()
print(word)

Why: word is what everything below it consumes, so the wrong expression here fails later and somewhere else. The lowercase copy is not stored anywhere, so word is untouched.

18. The original is unchanged

Worked example

word = "Hello"
word.lower()
print(word)

word.lower() makes a copy that is thrown away

Why: The lowercase copy is not stored anywhere, so word is untouched.

Read the output

Why: Verified by execution: prints Hello (still capitalized). You needed word = word.lower().

lineword
2Hello (copy discarded)
3Hello

19. What each one costs: The original is unchanged

Trade off

Comparison matrix

From The original is unchanged: every row here is a choice with a cost. Fill the word column, then say which row you would actually pick and what you give up for it.

lineword
2Hello (copy discarded)
3Hello

20. Something is wrong here: case-sensitive comparison

Anomaly

Predict first

A student writes this, and it looks reasonable:

Comparing raw input to "yes". The user types Yes.

It is wrong. Say what breaks — and say it before you turn the page.

Correct: "Yes" is not "yes" - the capital Y differs.

Lowercase first, then compare.

Why: "Yes" is not "yes" - the capital Y differs. So a perfectly reasonable answer is rejected.

21. Trap: case-sensitive comparison

Trap

The trap

Comparing raw input to "yes". The user types Yes.

answer = "Yes"
print(answer == "yes")

Different case is unequal

Why: "Yes" is not "yes" - the capital Y differs. So a perfectly reasonable answer is rejected.

expressionvalue
"Yes" == "yes"False

The fix

Lowercase first, then compare.

answer = "Yes"
print(answer.lower() == "yes")

.lower() makes the comparison case-blind

Why: answer.lower() is "yes", which matches. Real output: True. Now Yes, YES, and yes all pass.

expressionvalue
"Yes".lower() == "yes"True

22. Other handy case helpers

Concept

.title() capitalizes the first letter of each word ("ana lee".title() is "Ana Lee"), and .capitalize() capitalizes just the first letter of the whole string.

Like .lower(), these return a new string - use them mostly for display, and stick to .lower() when comparing.

23. Trimming Whitespace

Section

Part 3

24. .strip() removes edge spaces

Concept

.strip() removes spaces (and tabs/newlines) from the start and end of a string - great for cleaning up stray input.

25. Why is this step legal: Read the output

Explain it to yourself

Discussion prompt

In Trimming the ends this move is made:

Read the output

Why is that legal? Name the rule or definition it rests on before you read on.

Hint: If you can only say "because that is what you do", the rule is the thing to go and find.

Answer:

Verified by execution: Hello, then 5 (the spaces are gone).

26. Trimming the ends

Worked example

s = "  Hello  "
print(s.strip())
print(len(s.strip()))

Leading and trailing spaces go

Why: The word Hello remains, with no surrounding spaces.

Read the output

Why: Verified by execution: Hello, then 5 (the spaces are gone).

expressionvalue
s.strip()Hello
len(s.strip())5

27. Inspect it line by line: Trimming the ends

Error analysis

Annotate

Walk the callouts on Trimming the ends. Each one is a place this is easy to get subtly wrong.

  • The word Hello remains, with no surrounding spaces.
  • Verified by execution: Hello, then 5 (the spaces are gone).

28. Something is wrong here: strip does not touch inner spaces

Anomaly

Predict first

A student writes this, and it looks reasonable:

Expecting strip to remove ALL spaces.

It is wrong. Say what breaks — and say it before you turn the page.

Correct: The space between a and b is in the middle, so strip leaves it.

To remove inner spaces too, replace them.

Why: The space between a and b is in the middle, so strip leaves it. You get "a b", not "ab".

29. Trap: strip does not touch inner spaces

Trap

The trap

Expecting strip to remove ALL spaces.

s = "  a b  "
print(s.strip())

Only the edges are trimmed

Why: The space between a and b is in the middle, so strip leaves it. You get "a b", not "ab".

inputs.strip()
" a b ""a b"

The fix

To remove inner spaces too, replace them.

s = "  a b  "
print(s.strip().replace(" ", ""))

strip the ends, replace removes the rest

Why: .replace(" ", "") deletes every remaining space. Real output: ab. Pick the tool for where the spaces are.

stepvalue
strip()"a b"
replace(" ", "")"ab"

30. The clean pattern: strip then lower

Concept

Chain them: text.strip().lower() trims the ends and evens the case in one step - the standard way to normalize an answer.

Read left to right: strip first, then lower the result.

31. Where does each piece belong: Session 11 - Strings Toolkit

Sorting

Sort into buckets

These are the pieces of Session 11 - Strings Toolkit, out of order. Put each one back under the part of the lesson it belongs to.

Messy Text, Clean Code
Users type inconsistently; Be forgiving of the user; A string is a sequence of characters
Changing Case
.lower() and .upper(); Evening out the case; Methods return a new string
Trimming Whitespace
.strip() removes edge spaces; Trimming the ends; The clean pattern: strip then lower
s1
Messy Text, Clean Code is where Session 11 - Strings Toolkit puts Users type inconsistently, Be forgiving of the user, A string is a sequence of characters. Knowing which part of the lesson a problem belongs to is most of knowing which method to reach for.
s2
Changing Case is where Session 11 - Strings Toolkit puts .lower() and .upper(), Evening out the case, Methods return a new string. Knowing which part of the lesson a problem belongs to is most of knowing which method to reach for.
s3
Trimming Whitespace is where Session 11 - Strings Toolkit puts .strip() removes edge spaces, Trimming the ends, The clean pattern: strip then lower. Knowing which part of the lesson a problem belongs to is most of knowing which method to reach for.

32. Predict the next row: A robust yes check

Pattern

Predict first

The table runs: answer.strip() | "YES" · ...lower() | "yes"

In A robust yes check, given the rows so far: what is the next one — the row where step is == "yes"?

Correct: == "yes" | True

stepvalue
answer.strip()"YES"
...lower()"yes"
== "yes"True

Why: The relationship between the columns, not the individual numbers, is what generates the next row. " YES " becomes "yes" after strip and lower, which matches.

33. A robust yes check

Worked example

answer = "  YES "
if answer.strip().lower() == "yes":
    print("confirmed")

Clean, then compare

Why: " YES " becomes "yes" after strip and lower, which matches.

Read the output

Why: Verified by execution: prints confirmed. Now spaces and caps no longer matter.

stepvalue
answer.strip()"YES"
...lower()"yes"
== "yes"True

34. Watch it run: A robust yes check

Pattern

Step through it

Step through A robust yes check one row at a time. What is driving the change, and what would the row after the last one be?

  1. Step 1: step is answer.strip()
  2. Step 2: step is ...lower()
  3. Step 3: step is == "yes"

35. Searching Inside Text

Section

Part 4

36. in finds a substring

Concept

"ell" in "Hello" is True if that piece appears anywhere in the string. It is the substring test.

37. Is it in there?

Worked example

print("ell" in "Hello")
print("xyz" in "Hello")

in scans the whole string

Why: ell appears inside Hello; xyz does not.

Read the output

Why: Verified by execution: True then False.

expressionvalue
"ell" in "Hello"True
"xyz" in "Hello"False

38. Draw the shape of it: Is it in there?

Blank canvas

Draw it

Draw what Is it in there? just did — the shape of it, not the line-by-line working. One picture, labels only where you need them. Then check it against the steps: anything you could not draw is a step you followed rather than understood.

39. Spot a keyword anywhere

Concept

Combine cleaning with in to catch a keyword no matter the case or surrounding words: "bye" in message.lower().

This upgrades a chatbot from exact-match to 'reacts if the word appears at all'.

40. Restore the missing line: A keyword-spotting bot

Fill the middle

Fill in the blanks

From A keyword-spotting bot — one line has had its right-hand side removed. Put it back.

message = "Ok BYE now"
if "bye" in message.lower():
print("Goodbye!")

Why: message is what everything below it consumes, so the wrong expression here fails later and somewhere else. message.lower() is "ok bye now", which contains "bye".

41. A keyword-spotting bot

Worked example

message = "Ok BYE now"
if "bye" in message.lower():
    print("Goodbye!")

Lowercase, then look for the keyword

Why: message.lower() is "ok bye now", which contains "bye".

Read the output

Why: Verified by execution: prints Goodbye! - even though bye was capitalized and mid-sentence.

message.lower()"bye" in it?
ok bye nowTrue

42. Inspect it line by line: A keyword-spotting bot

Error analysis

Annotate

Walk the callouts on A keyword-spotting bot. Each one is a place this is easy to get subtly wrong.

  • message.lower() is "ok bye now", which contains "bye".
  • Verified by execution: prints Goodbye! - even though bye was capitalized and mid-sentence.

43. .startswith() and .endswith()

Concept

text.startswith("http") and text.endswith(".py") check the beginning or end of a string - returning a bool.

44. Checking a file extension

Worked example

name = "report.py"
print(name.endswith(".py"))
print(name.startswith("report"))

Check the ends

Why: It ends with .py and starts with report.

Read the output

Why: Verified by execution: True then True.

callvalue
endswith(".py")True
startswith("report")True

45. Length, Index, Slice

Section

Part 5

46. len() counts characters

Concept

len("Hello") is 5 - the number of characters, spaces included.

47. How long is it?

Worked example

print(len("Hello"))
print(len("a b"))

Every character counts, spaces too

Why: Hello is 5; "a b" is 3 (a, space, b).

Read the output

Why: Verified by execution: 5 then 3.

stringlen
Hello5
a b3

48. Fill in: len for How long is it?

Comparison

Comparison matrix

From How long is it?: refill the len column from what you know. The rest of the table is as it appeared.

stringlen
Hello5
a b3

49. Index a character (from 0)

Concept

"Hello"[0] is the first character, "H". Just like lists, indexing starts at 0.

50. First and last character

Worked example

word = "Hello"
print(word[0])
print(word[-1])

0 is first, -1 is last

Why: word[0] is H; word[-1] is o.

Read the output

Why: Verified by execution: H then o.

indexchar
0H
-1o

51. Slice a piece: s[a:b]

Concept

"Hello"[0:3] takes characters at index 0, 1, 2 - "Hel". The end index is excluded, like range.

Leave a side blank to go to the edge: word[1:] is everything from index 1 on.

52. Taking a substring

Worked example

word = "Hello"
print(word[0:3])
print(word[1:])

0:3 is indexes 0, 1, 2

Why: The character at index 3 is excluded.

1: goes to the end

Why: Verified by execution: Hel then ello.

slicevalue
word[0:3]Hel
word[1:]ello

53. Something is wrong here: strings are immutable

Anomaly

Predict first

A student writes this, and it looks reasonable:

Trying to change one character in place.

It is wrong. Say what breaks — and say it before you turn the page.

Correct: Strings are immutable - they never change once made.

Build a new string instead.

Why: Strings are immutable - they never change once made. Assigning to s[0] raises a TypeError.

54. Trap: strings are immutable

Trap

The trap

Trying to change one character in place.

s = "hi"
s[0] = "H"

You cannot assign to a character

Why: Strings are immutable - they never change once made. Assigning to s[0] raises a TypeError.

you writeresult
s[0] = "H"TypeError: 'str' object does not support item assignment

The fix

Build a new string instead.

s = "hi"
s = "H" + s[1:]
print(s)

Make a fresh string and rebind s

Why: "H" + s[1:] is "H" + "i" = "Hi". Real output: Hi. To 'change' a string, create a new one.

expressionvalue
"H" + s[1:]Hi

55. Which of these survive contact with Session 11 - Strings Toolkit?

Two truths and a lie

Sort into buckets

Some of these hold up and some are the exact mistakes this lesson is built to prevent. Sort them.

Holds up
One user types yes, another YES, another Yes . All mean the same thing - but to Python they are three different strings.; Good programs meet people where they are. Rather than demand perfect input, clean it up: trim the spaces, even out the case, then compare.; "Hello" is really the ordered characters H, e, l, l, o. You can measure it, index into it, and slice pieces out.
Breaks
Comparing raw input to "yes". The user types Yes.; Expecting strip to remove ALL spaces.
sound
These are stated as this lesson states them — each one survives the edge cases Session 11 - Strings Toolkit puts it through.
flawed
Each of these is lifted from a trap in this deck: reasonable-sounding, and wrong in a way that only shows up once you rely on it.

56. Splitting & Replacing

Section

Part 6

57. .split() breaks text into a list

Concept

text.split() with no argument splits on whitespace, giving a list of words.

This is the bridge from a sentence to something you can loop over or count.

58. Restore the missing line: Sentence into words

Fill the middle

Fill in the blanks

From Sentence into words — one line has had its right-hand side removed. Put it back.

text = "one two three"
words = text.split()
print(words)
print(len(words))

Why: words is what everything below it consumes, so the wrong expression here fails later and somewhere else. Verified by execution: ['one', 'two', 'three'], then 3.

59. Sentence into words

Worked example

text = "one two three"
words = text.split()
print(words)
print(len(words))

split hands back a list

Why: Each run of spaces becomes a separator.

Now len counts words

Why: Verified by execution: ['one', 'two', 'three'], then 3.

expressionvalue
text.split()['one', 'two', 'three']
len(words)3

60. Split on a delimiter

Concept

Pass a separator to split on it: "a,b,c".split(",") gives ['a', 'b', 'c'] - handy for CSV-style text.

61. Why is this step legal: Read the output

Explain it to yourself

Discussion prompt

In Splitting a comma list this move is made:

Read the output

Why is that legal? Name the rule or definition it rests on before you read on.

Hint: If you can only say "because that is what you do", the rule is the thing to go and find.

Answer:

Verified by execution: ['apple', 'pear', 'plum'].

62. Splitting a comma list

Worked example

csv = "apple,pear,plum"
print(csv.split(","))

The comma is the separator

Why: Each comma marks a break between items.

Read the output

Why: Verified by execution: ['apple', 'pear', 'plum'].

expressionvalue
csv.split(",")['apple', 'pear', 'plum']

63. .replace() swaps text

Concept

text.replace(old, new) returns a copy with every old swapped for new.

Like other methods, it returns a new string - store it if you want to keep the change.

64. What rests on this: .replace() swaps text

Socratic

Discussion prompt

text.replace(old, new) returns a copy with every old swapped for new.

Suppose that were not true. What is the first thing in Session 11 - Strings Toolkit that would stop working?

Hint: Follow it one step downstream. The answer is whatever was quietly relying on it.

Answer:

Like other methods, it returns a new string - store it if you want to keep the change.

65. Swapping words

Worked example

s = "I like cats"
print(s.replace("cats", "dogs"))

Every match is replaced

Why: cats becomes dogs.

Read the output

Why: Verified by execution: I like dogs.

expressionvalue
s.replace("cats", "dogs")I like dogs

66. f-strings, Revisited

Section

Part 7

67. f-strings drop values into text

Concept

Put f before the quotes and wrap each value in { }. Cleaner than gluing with +, and it converts values for you.

68. Teach it back: f-strings drop values into text

Explain it

Discussion prompt

Explain f-strings drop values into text to a student a year behind you. No notation, no jargon they have not met — and it still has to be true.

Hint: If your explanation needs a symbol they have never seen, you are describing the notation rather than the idea.

Answer:

Put f before the quotes and wrap each value in { }. Cleaner than gluing with +, and it converts values for you.

69. Building a line

Worked example

name = "Ana"
score = 3
print(f"{name} scored {score}")

Each brace is filled with a value

Why: {name} -> Ana, {score} -> 3.

Read the output

Why: Verified by execution: Ana scored 3.

blankfills with
{name}Ana
{score}3

70. Format numbers inside braces

Concept

Add :.2f for two decimals, or :>8 to right-align in a field - useful for tidy tables and money.

71. By analogy: Format numbers inside braces

Analogy

Discussion prompt

Explain Format numbers inside braces by analogy to something with no Python Fundamentals in it at all — a queue, a recipe, a map, a bank balance, whatever fits. Then say where your analogy breaks.

Hint: An analogy that never breaks is not an analogy, it is the same idea wearing a hat. Find the seam — that is the part that is actually new.

Answer:

Add :.2f for two decimals, or :>8 to right-align in a field - useful for tidy tables and money.

72. Two-decimal money

Worked example

price = 4.5
print(f"Total: ${price:.2f}")

:.2f shows two decimal places

Why: 4.5 displays as 4.50.

Read the output

Why: Verified by execution: Total: $4.50.

valueshown as
4.5$4.50

73. Draw the shape of it: Two-decimal money

Blank canvas

Draw it

Draw what Two-decimal money just did — the shape of it, not the line-by-line working. One picture, labels only where you need them. Then check it against the steps: anything you could not draw is a step you followed rather than understood.

74. Build: a Text Analyzer

Section

Part 8

75. Count words with split + len

Concept

len(text.split()) is the word count: split into a list of words, then count the list.

76. Break it if you can: Count words with split + len

Counterexample

Discussion prompt

len(text.split()) is the word count: split into a list of words, then count the list.

That is stated as though it always holds. Do one of two things: produce a case where it fails, or say precisely what rules such a case out. "It just does" is not on the menu.

Hint: Hunt at the extremes first — zero, one, negative, empty, equal. If every extreme survives, the reason they survive is the proof.

77. Why is this step legal: in checks for a keyword

Explain it to yourself

Discussion prompt

In Words and a keyword this move is made:

in checks for a keyword

Why is that legal? Name the rule or definition it rests on before you read on.

Hint: If you can only say "because that is what you do", the rule is the thing to go and find.

Answer:

Verified by execution: words: 4, then has 'fox': True.

78. Words and a keyword

Worked example

text = "the quick brown fox"
print("words:", len(text.split()))
print("has 'fox':", "fox" in text.lower())

split then len counts words

Why: Four words in the sentence.

in checks for a keyword

Why: Verified by execution: words: 4, then has 'fox': True.

measurevalue
word count4
contains foxTrue

79. What each one costs: Words and a keyword

Trade off

Comparison matrix

From Words and a keyword: every row here is a choice with a cost. Fill the value column, then say which row you would actually pick and what you give up for it.

measurevalue
word count4
contains foxTrue

80. Guess the shape of the answer: Normalize then compare

Estimation

Predict first

The user types Paris (extra spaces, mixed case can vary):

Commit before you compute: what does Normalize then compare come out to? A rough magnitude and the right form is enough — the point is to have something concrete to be wrong about.

Correct: Read the output

Why: A prediction you can defend turns the computation into a check rather than a leap of faith — and an answer that contradicts it is caught on the spot. Verified by execution: prints correct - forgiving of spaces and case.

81. Normalize then compare

Worked example

The user types Paris (extra spaces, mixed case can vary):

guess = "  Paris  "
if guess.strip().lower() == "paris":
    print("correct")

Clean the guess, then compare to the lowercase answer

Why: strip and lower make "paris", which matches.

Read the output

Why: Verified by execution: prints correct - forgiving of spaces and case.

stepvalue
guess.strip()"Paris"
...lower()"paris"
== "paris"True

82. Fill in: value for Normalize then compare

Comparison

Comparison matrix

From Normalize then compare: refill the value column from what you know. The rest of the table is as it appeared.

stepvalue
guess.strip()"Paris"
...lower()"paris"
== "paris"True

83. Patterns & Checks

Section

Part 9

84. Cleaning user text

Pattern

1. Normalize: text.strip().lower()

Why: Trims stray spaces and evens the case so comparisons are forgiving.

2. Match: == for exact, in for 'contains'

Why: cleaned == "yes" for a whole answer; keyword in cleaned to spot a word anywhere.

3. Remember methods return a NEW string

Why: text = text.lower(); the original never changes on its own.

4. Split to count or loop; f-strings to display

Why: len(text.split()) counts words; f"{x}" builds clean output.

85. Why is this step legal: Shape: len, [i], [a:b], .split(), .replace()

Explain it to yourself

Discussion prompt

In String toolkit at a glance this move is made:

Shape: len, [i], [a:b], .split(), .replace()

Why is that legal? Name the rule or definition it rests on before you read on.

Hint: If you can only say "because that is what you do", the rule is the thing to go and find.

Answer:

Measure, index, slice, break apart, and swap - strings are immutable, so these return new strings.

86. String toolkit at a glance

Pattern

Case: .lower() / .upper()

Why: Even out capitalization before comparing.

Trim: .strip(); search: in, .startswith, .endswith

Why: strip trims the ends only; in tests a substring anywhere.

Shape: len, [i], [a:b], .split(), .replace()

Why: Measure, index, slice, break apart, and swap - strings are immutable, so these return new strings.

87. Where this shows up: Session 11 - Strings Toolkit

Real world

Discussion prompt

Outside this lesson: where does Session 11 - Strings Toolkit actually turn up? Name one concrete situation — a job, a piece of software someone ships, a decision somebody has to make — and say which part of String toolkit at a glance is doing the work in it.

Hint: Vague is the failure mode here. "Engineering" is not a situation; "deciding whether this build is fast enough to ship" is.

Answer:

Session 11 of the Python Fundamentals series, in depth. Cleaning and shaping text so messy user input behaves: .lower()/.upper(), .strip(), the in keyword for substrings, .startswith()/.endswith(), length, indexing and slicing, .split() and .replace(), and f-strings with formatting.

88. Check: method returns a copy

Check

Was word changed?

word = "Hi"
word.upper()
print(word)
stored?word
no?

Check your understanding

What does this print?

  • A. Hi (correct)
  • B. HI
  • C. hi
  • D. Error

Answer: A

Why: word.upper() returns a new uppercase string but it is not stored, so word is unchanged. You would need word = word.upper(). Verified by execution.

Why B tempts people
HI would require storing the result: word = word.upper(). The bare call is discarded.
Why C tempts people
The original is Hi (capital H); nothing lowercased it.
Why D tempts people
Calling .upper() is valid - it just returns a copy that goes unused.

89. Check: clean and compare

Check

The answer has spaces and caps.

a = "  YES "
print(a.strip().lower() == "yes")
cleaned== yes
??

Check your understanding

What does this print?

  • A. True (correct)
  • B. False
  • C. yes
  • D. Error

Answer: A

Why: strip removes the spaces and lower makes it "yes", which equals "yes", so the result is True. Verified by execution.

Why B tempts people
After cleaning, the strings match, so it is True, not False.
Why C tempts people
The comparison returns a bool, not the cleaned string.
Why D tempts people
Chaining strip and lower is valid - no error.

90. Check: slicing

Check

Which characters?

s = "Python"
print(s[0:3])
index0,1,2
chars?

Check your understanding

What does this print?

  • A. Pyt (correct)
  • B. Pyth
  • C. yth
  • D. Pytho

Answer: A

Why: s[0:3] takes indexes 0, 1, 2 (P, y, t) and excludes index 3, giving Pyt. Verified by execution.

Why B tempts people
Index 3 (h) is excluded - the slice stops before the end value.
Why C tempts people
Slicing starts at index 0 here (P), not index 1.
Why D tempts people
That would be s[0:5]; s[0:3] stops after three characters.

91. Check: substring

Check

Does the piece appear?

print("cat" in "category")
expressionvalue
"cat" in "category"?

Check your understanding

What does this print?

  • A. True (correct)
  • B. False
  • C. cat
  • D. 3

Answer: A

Why: cat appears at the start of category, so the substring test is True. Verified by execution.

Why B tempts people
The letters c-a-t do appear together in category, so it is True.
Why C tempts people
in returns a bool, not the substring.
Why D tempts people
in does not return a position or count - just True or False.

92. Check: word count

Check

How many words?

text = "a b c d"
print(len(text.split()))
split()len
??

Check your understanding

What does this print?

  • A. 4 (correct)
  • B. 7
  • C. 1
  • D. 3

Answer: A

Why: split() breaks on spaces into ['a', 'b', 'c', 'd'], and len of that is 4. Verified by execution.

Why B tempts people
7 is len of the whole string (including spaces), not the word count. split() must run first.
Why C tempts people
Without split(), len would be on the string; with split() it counts 4 words.
Why D tempts people
There are four words (a, b, c, d), not three.

93. Check: immutability

Check

Can you edit one character?

s = "cat"
s[0] = "b"
assign s[0]?result
??

Check your understanding

What happens?

  • A. TypeError - strings are immutable (correct)
  • B. s becomes bat
  • C. s becomes b
  • D. Nothing changes

Answer: A

Why: Strings cannot be changed in place, so assigning to s[0] raises a TypeError. Build a new string: s = "b" + s[1:]. Verified by execution.

Why B tempts people
You cannot edit a character in place - it errors before any change.
Why C tempts people
Nothing is reassigned successfully; the line raises an error.
Why D tempts people
It is not silently ignored - it crashes with a TypeError.

94. Connect it up: Session 11 - Strings Toolkit

Connect it up

Draw it

One page, no notation unless you need it: draw how these connect — Messy Text, Clean Code · Changing Case · Trimming Whitespace · Searching Inside Text · Length, Index, Slice · Splitting & Replacing. Put an arrow wherever one of them is what makes another possible, and label the arrow with why.

95. What you can do now

Recap

Normalize with .strip().lower(), search with in / .startswith / .endswith, and shape with len, slicing, .split(), .replace(), and f-strings.

You wantUse
case-blind comparea.strip().lower() == b
keyword anywhereword in text.lower()
a piece of the texttext[a:b]
words as a listtext.split()
swap texttext.replace(old, new)

Remember: strings are immutable, and methods return a new string. Next session we stop fearing red error text - reading tracebacks and handling errors with try / except.

Sources

  1. Python 3 Library Reference - String Methods
  2. Python 3 Tutorial - Strings (indexing and slicing)
  3. All snippets and error messages executed and copied from CPython 3.12. — Author verification run, 2026-07-15 (Python Fundamentals series, Session 11).

Want this taught 1-on-1? Alexander tutors Python Fundamentals — $55/session, free consultation.

Book on Wyzant · Text (657) 465-8108