Python, Concept by Concept

unit

Strings

A space club has badge names, coded signals, and messages to inspect. Your challenge is to reach the exact characters you need, clean messy text, and build tools that transform or search a message.

By the end, you will build a secret-message shifter, a position tool, and an alphabet scan report.

You will learn

  • Find a character by its position and take part of a string with a slice.
  • Clean, test, split, and join text with string methods.
  • Check whether a character appears in text with in.
  • Build a new string one character at a time and search for a match.

Lesson 1: Reach into a String

Build badge initials

A string is a sequence of characters. Each character has a numbered position called an index. Python starts numbering at 0, so [0] reaches the first character. Reach the first character of each name to build initials.

first_name = "Maya"
last_name = "Chen"
initials = first_name[0] + last_name[0]
print(initials)

Output

MC

Notice

The initials are MC. The brackets reach one character, so first_name[0] is itself a one-character string. Meaningful names such as first_name and initials help a reader understand the job.

Now reach the last character with index -1. Negative indexes count backward from the end.

print(first_name[-1])

Output

a

Notice

-1 selects a, the last character of Maya. Positive indexes still count from the front.

Cut out a substring with a slice

A slice reaches a section of a string. In text[a:b], position a is included and position b is excluded. This is the same stop rule used by range(a, b).

signal = "ORBIT-739"
word_part = signal[0:5]
number_part = signal[6:9]

print(word_part)
print(number_part)

Output

ORBIT
739

Visible payoff: the two lines print ORBIT and then 739. The first slice includes positions 0 through 4 but stops before 5. The second includes positions 6 through 8 but stops before 9. A slice is still a string, even when it contains only part of the original string.

Leave one slice end open

An omitted start begins at the first character. Try word[:3].

word = "galaxy"
print(word[:3])

Output

gal

Notice

word[:3] prints gal; position 3 is excluded.

An omitted stop continues to the end. Try word[3:].

print(word[3:])

Output

axy

Notice

word[3:] prints axy. The two open-ended slices cover the whole word.

Reverse with one special slice

The reversing slice [::-1] reads a string from its last character back to its first.

print(word[::-1])

Output

yxalag

Notice

The result is yxalag. This is the only step slice used in this unit.

Recall len from Unit 07

len(text) counts the characters in a string, as it did in Unit 07. Spaces and punctuation are characters too. Measure a badge label next.

call_sign = "Blue Fox"
size = len(call_sign)

print(f"Badge text: {call_sign}")
print("Characters: " + str(size))

Output

Badge text: Blue Fox
Characters: 8

The f-string places the string value directly in a report. The next report uses str(size) to convert the integer 8 into text before concatenating with +.

Lesson 2: Clean and Test

Repair a messy signal

A control panel receives extra spaces and mixed capital letters. String methods are small tools attached to a string value. Start with upper(), which makes uppercase text.

signal = "Red Comet"
print(signal.upper())

Output

RED COMET

Notice

upper() prints RED COMET and does not change signal.

Now use lower() to make a separate lowercase version.

print(signal.lower())

Output

red comet

Notice

The result is red comet; the saved signal is still Red Comet.

Extra spaces at the beginning and end of a received line can be removed with strip().

raw_signal = "  RED COMET  "
print(raw_signal.strip())

Output

RED COMET

Notice

The printed text has no spaces at either end. strip() leaves internal spaces in place.

To change a matching piece of text, use replace(old, new).

print("red comet".replace("red", "blue"))

Output

blue comet

Notice

The result is blue comet; the old text was not edited in place.

Now chain the four methods to clean, change, and announce one signal.

raw_signal = "  RED COMET  "
clean_signal = raw_signal.strip().lower()
changed_signal = clean_signal.replace("red", "blue")
loud_signal = changed_signal.upper()

print(clean_signal)
print(changed_signal)
print(loud_signal)

Output

red comet
blue comet
BLUE COMET

Notice

The chain prints red comet, blue comet, and BLUE COMET. strip() removes spaces only at the ends, and every method returns a new string. The original raw_signal stays unchanged. Because strip() returns a string, you can call .lower() on that result right away.

Find and recognize text

find(piece) reports the first matching position, or -1 when no match exists.

message = "moon rover"
print(message.find("rover"))
print(message.find("sun"))

Output

5
-1

Notice

The positions are 5 and -1. A missing piece has no string index.

startswith checks the beginning; endswith checks the end. Both return a boolean.

filename = "mission.py"
print(filename.startswith("mission"))
print(filename.endswith(".py"))

Output

True
True

Notice

Both checks are True; the methods test different ends of the same string.

isdigit() checks that every character is a digit; isalpha() checks that every character is a letter.

print("4071".isdigit())
print("orbit".isalpha())
print("-3".isdigit())

Output

True
True
False

Notice

The first two checks are True; "-3".isdigit() is False, so this simple digit check does not accept negative numbers.

Join characters and walk words

A separator string can join the characters of another string.

print("-".join("abc"))

Output

a-b-c

Notice

The result is a-b-c. The separator goes between characters, with none at either end.

split() lets a loop visit words separated by whitespace. Walk the words directly, without indexing the collection that split() returns.

line = "stars need fuel"
for word in line.split():
    print(word)

Output

stars
need
fuel

Notice

The loop prints stars, need, and fuel on separate lines. Each word is a string, so word[0] may reach its first character.

Test membership

The in operator asks whether a character or substring appears in a string. It returns a boolean. Matching is case-sensitive, so cleaning case first can make a test dependable. The two tests below print True and then False.

message = "Launch at Dawn"
quiet_message = message.lower()

print("dawn" in quiet_message)
print("moon" in quiet_message)

Output

True
False

Try real input: read a PIN and check whether it has exactly four digits.

Try it yourself

pin = input("PIN: ")
if len(pin) != 4:
    print(False)
elif not pin.isdigit():
    print(False)
else:
    print(True)

Notice

len checks the width and isdigit() rejects letters; this check also rejects a leading minus sign.

Test a palindrome from both ends

A palindrome reads the same from left to right and right to left. Before checking both ends, walk through the positions of one short word.

w = "level"
for i in range(len(w)):
    print(i, w[i])

Output

0 l
1 e
2 v
3 e
4 l

Notice

The loop reports positions 0 through 4 and their characters. An index loop gives both a position and the character at that position.

Next compare just one mirror pair: the first and last characters.

w = "level"
i = 0
print(w[i] == w[len(w) - 1 - i])

Output

True

Notice

This one pair matches. A full palindrome check repeats the mirror comparison for half the word.

Now clean spaces and case, compare every mirror pair, and leave early at a mismatch.

def is_palindrome(text):
    cleaned = text.lower().replace(" ", "")
    for i in range(len(cleaned) // 2):
        if cleaned[i] != cleaned[len(cleaned) - 1 - i]:
            return False
    return True

print(is_palindrome("Never odd or even"))
print(is_palindrome("space camp"))

Output

True
False

For each loop counter i, the left position is i and the matching right position is len(cleaned) - 1 - i. A mismatch returns False immediately. return True belongs after the loop because every tested pair must match first.

Try real input: read a word or phrase and ask the palindrome function about it.

Try it yourself

word = input("Word: ")
print(is_palindrome(word))

Notice

The typed text replaces the fixed sample; the function returns one boolean.

Count vowels by condition

A counter can grow only when the current character passes a membership test. The report below prints Vowels: 5.

A for loop can walk directly through a string: for ch in text: gives each character in order. This is a value loop: use it when the character itself matters. An index loop such as for i in range(len(text)): is different: it gives positions, as in the palindrome example above and the position example later.

word = "sun"
for ch in word:
    print(ch)

Output

s
u
n

Notice

The loop prints s, u, and n in order. It visits characters directly, without using their indexes.

Now count only characters that are vowels, using a condition inside the character loop.

def vowel_count(text):
    total = 0
    cleaned = text.lower()
    for ch in cleaned:
        if ch in "aeiou":
            total = total + 1
    return total

amount = vowel_count("Solar eclipse")
print(f"Vowels: {amount}")

Output

Vowels: 5

Choose among three character kinds

Membership tests also fit an if / elif / else branch. Test the narrow vowel case first, the wider alphabet case second, and everything else last. The three calls below print vowel, consonant, and other.

def character_kind(ch):
    letter = ch.lower()
    if letter in "aeiou":
        return "vowel"
    elif letter in "abcdefghijklmnopqrstuvwxyz":
        return "consonant"
    else:
        return "other"

print(character_kind("E"))
print(character_kind("z"))
print(character_kind("?"))

Output

vowel
consonant
other

Lesson 3: Transform and Search

Build a new string one character at a time

A transmission effect needs every character doubled. Strings can be accumulated with +: begin with an empty string, transform each character, and save the growing result.

def double_letters(text):
    transformed = ""
    for ch in text:
        transformed = transformed + ch + ch
    return transformed

print(double_letters("Go!"))
print(double_letters("42"))

Output

GGoo!!
4422

Visible payoff: the calls print GGoo!! and then 4422. The accumulator transformed starts empty. Each loop trip adds the current character twice. The function returns a new string; it does not change text. This is the transform-each pattern.

Try real input: read one line, count its words, and print the count.

Try it yourself

line = input("Line: ")
count = 0
for word in line.split():
    count = count + 1
print(f"Words: {count}")

Notice

Each word contributes one to the count, including words after extra spaces.

Search from left to right

A navigation display needs the first position of one character. Visit positions in order. Return the loop counter as soon as the character matches, or return -1 only after the whole loop ends.

def position(text, ch):
    for i in range(len(text)):
        if text[i] == ch:
            return i
    return -1

print(position("meteor", "e"))
print(position("meteor", "x"))

Output

1
-1

The first call returns the integer 1. The second returns -1, the signal that no position matched. Returning inside the loop preserves the first match. Returning -1 inside the loop would stop too early. The short report below prints Saved position: 4.

saved_position = position("satellite", "l")
report = "Saved position: " + str(saved_position)
print(report)

Output

Saved position: 4

Count one chosen character

Searching for the first match and counting every match are related but different jobs. For a character count, keep walking after a match and update an integer counter. The two calls below print 2 and then 0.

def count_char(text, ch):
    matches = 0
    for current in text:
        if current == ch:
            matches = matches + 1
    return matches

print(count_char("balloon", "l"))
print(count_char("balloon", "z"))

Output

2
0

Print an alphabet scan table

A report can scan the alphabet one letter at a time. The outer loop chooses a letter, and count_char scans the message for that letter. print writes one table row per alphabet letter.

def print_letter_table(text):
    alphabet = "abcdefghijklmnopqrstuvwxyz"
    cleaned = text.lower()
    print("letter | total")
    for letter in alphabet:
        total = count_char(cleaned, letter)
        print(f"{letter} | {total}")

print_letter_table("Cabana!")

Output

letter | total
a | 3
b | 1
c | 1
d | 0
e | 0
f | 0
g | 0
h | 0
i | 0
j | 0
k | 0
l | 0
m | 0
n | 1
o | 0
p | 0
q | 0
r | 0
s | 0
t | 0
u | 0
v | 0
w | 0
x | 0
y | 0
z | 0

The table always has one row for each of the 26 lowercase letters. For Cabana!, the nonzero rows are a | 3, b | 1, c | 1, and n | 1; all other rows show 0. It reports every total without choosing a winning letter. The loops make each scan step visible.

Challenge: Shift a message

A Caesar shift moves each letter forward through the alphabet. Build the search helper first. Then lowercase the message, search the alphabet for each character, and use remainder arithmetic to wrap from z to a. Nonletters pass through unchanged. Here k >= 0.

def position(alphabet, ch):
    for i in range(len(alphabet)):
        if alphabet[i] == ch:
            return i
    return -1

def shift(message, k):
    alphabet = "abcdefghijklmnopqrstuvwxyz"
    shifted = ""
    cleaned = message.lower()
    for ch in cleaned:
        pos = position(alphabet, ch)
        if pos == -1:
            shifted = shifted + ch
        else:
            new_pos = (pos + k) % 26
            shifted = shifted + alphabet[new_pos]
    return shifted

print(shift("Meet at 8!", 3))
print(shift("Zebra", 2))

Output

phhw dw 8!
bgdtc

Challenge payoff: the calls print phhw dw 8! and then bgdtc.

Put it together: indexing reaches one character, and slices reach a section or reverse a string. The string methods taught here clean, inspect, and join text; in tests membership. Counter loops measure matches, transform-each loops build new strings, and a left-to-right search returns a position or -1.

Recap

  • text[0] reaches the first character; text[1:4] takes positions 1 through 3.
  • String methods can change case, trim spaces, replace text, or split a line into words.
  • in tests whether a character or smaller string appears in a string.
  • A loop can add transformed characters to a new string without changing the original.
  • A search checks positions in order and can return the match's position or -1.

You can now inspect, clean, transform, and search the space club's messages.

Go to the exercises (29)

For parents and teachers: report a problem