You're building a greeting card generator. The user enters their name "Alice" and you need to create "Hello, Alice!" - combining text, storing it, measuring it, and accessing individual letters.

Store and print a name

Create a string and display it.

name
name.py
Replay: real traced execution (multi-file project)
name = "Alice"
print(f"Hello, {name}!")
print(f"Your name is: {name}")
name = "Bob"
print(f"Hello, {name}!")
print(f"Your name is: {name}")
name = "Charlie"
print(f"Hello, {name}!")
print(f"Your name is: {name}")
  1. name ← Alice

    1name→ Alice = "Alice"  #@name="Bob", "Charlie"2print(f"Hello, {nameAlice}!")3print(f"Your name is: {nameAlice}")
    outputHello, Alice!
    Your name is: Alice
  1. name ← Bob

    1name→ Bob = "Bob"2print(f"Hello, {nameBob}!")3print(f"Your name is: {nameBob}")
    outputHello, Bob!
    Your name is: Bob
  1. name ← Charlie

    1name→ Charlie = "Charlie"2print(f"Hello, {nameCharlie}!")3print(f"Your name is: {nameCharlie}")
    outputHello, Charlie!
    Your name is: Charlie

Strings can use single or double quotes - your choice.

str A sequence of characters, like `"Hello"`. Immutable in Python.

Combine first and last name

Join strings using + or f-strings.

example
combine.py
Replay: real traced execution (multi-file project)
first_name = "Alice"
last_name = "Smith"

# Using + operator
full_name = first_name + " " + last_name
print("Full name: " + full_name)

# Using f-string (preferred)
greeting = f"Hello, {first_name} {last_name}!"
print(greeting)

# Using .join()
parts = [first_name, last_name]
joined = " ".join(parts)
print(f"Joined: {joined}")
first_name = "Bob"
last_name = "Smith"

# Using + operator
full_name = first_name + " " + last_name
print("Full name: " + full_name)

# Using f-string (preferred)
greeting = f"Hello, {first_name} {last_name}!"
print(greeting)

# Using .join()
parts = [first_name, last_name]
joined = " ".join(parts)
print(f"Joined: {joined}")
first_name = "Charlie"
last_name = "Smith"

# Using + operator
full_name = first_name + " " + last_name
print("Full name: " + full_name)

# Using f-string (preferred)
greeting = f"Hello, {first_name} {last_name}!"
print(greeting)

# Using .join()
parts = [first_name, last_name]
joined = " ".join(parts)
print(f"Joined: {joined}")
first_name = "Alice"
last_name = "Jones"

# Using + operator
full_name = first_name + " " + last_name
print("Full name: " + full_name)

# Using f-string (preferred)
greeting = f"Hello, {first_name} {last_name}!"
print(greeting)

# Using .join()
parts = [first_name, last_name]
joined = " ".join(parts)
print(f"Joined: {joined}")
first_name = "Alice"
last_name = "Lee"

# Using + operator
full_name = first_name + " " + last_name
print("Full name: " + full_name)

# Using f-string (preferred)
greeting = f"Hello, {first_name} {last_name}!"
print(greeting)

# Using .join()
parts = [first_name, last_name]
joined = " ".join(parts)
print(f"Joined: {joined}")
  1. first_name ← Alice, last_name ← Smith, full_name ← Alice Smith

    1first_name→ Alice = "Alice"  #@first_name="Bob", "Charlie"2last_name→ Smith = "Smith"   #@last_name="Jones", "Lee"34# Using + operator5full_name→ Alice Smith = first_nameAlice + " " + last_nameSmith6print("Full name: " + full_nameAlice Smith)78# Using f-string (preferred)9greeting→ Hello, Alice Smith! = f"Hello, {first_nameAlice} {last_nameSmith}!"10print(greetingHello, Alice Smith!)1112# Using .join()13parts→ ['Alice', 'Smith'] = [first_nameAlice, last_nameSmith]14joined→ Alice Smith = " ".join(parts['Alice', 'Smith'])15print(f"Joined: {joinedAlice Smith}")
    outputFull name: Alice Smith
    Hello, Alice Smith!
    Joined: Alice Smith
  1. first_name ← Bob, last_name ← Smith, full_name ← Bob Smith, greeting ← Hello, Bob Smith!

    1first_name→ Bob = "Bob"2last_name→ Smith = "Smith"34# Using + operator5full_name→ Bob Smith = first_nameBob + " " + last_nameSmith6print("Full name: " + full_nameBob Smith)78# Using f-string (preferred)9greeting→ Hello, Bob Smith! = f"Hello, {first_nameBob} {last_nameSmith}!"10print(greetingHello, Bob Smith!)1112# Using .join()13parts→ ['Bob', 'Smith'] = [first_nameBob, last_nameSmith]14joined→ Bob Smith = " ".join(parts['Bob', 'Smith'])15print(f"Joined: {joinedBob Smith}")
    outputFull name: Bob Smith
    Hello, Bob Smith!
    Joined: Bob Smith
  1. first_name ← Charlie, last_name ← Smith, full_name ← Charlie Smith

    1first_name→ Charlie = "Charlie"2last_name→ Smith = "Smith"34# Using + operator5full_name→ Charlie Smith = first_nameCharlie + " " + last_nameSmith6print("Full name: " + full_nameCharlie Smith)78# Using f-string (preferred)9greeting→ Hello, Charlie Smith! = f"Hello, {first_nameCharlie} {last_nameSmith}!"10print(greetingHello, Charlie Smith!)1112# Using .join()13parts→ ['Charlie', 'Smith'] = [first_nameCharlie, last_nameSmith]14joined→ Charlie Smith = " ".join(parts['Charlie', 'Smith'])15print(f"Joined: {joinedCharlie Smith}")
    outputFull name: Charlie Smith
    Hello, Charlie Smith!
    Joined: Charlie Smith
  1. first_name ← Alice, last_name ← Jones, full_name ← Alice Jones

    1first_name→ Alice = "Alice"2last_name→ Jones = "Jones"34# Using + operator5full_name→ Alice Jones = first_nameAlice + " " + last_nameJones6print("Full name: " + full_nameAlice Jones)78# Using f-string (preferred)9greeting→ Hello, Alice Jones! = f"Hello, {first_nameAlice} {last_nameJones}!"10print(greetingHello, Alice Jones!)1112# Using .join()13parts→ ['Alice', 'Jones'] = [first_nameAlice, last_nameJones]14joined→ Alice Jones = " ".join(parts['Alice', 'Jones'])15print(f"Joined: {joinedAlice Jones}")
    outputFull name: Alice Jones
    Hello, Alice Jones!
    Joined: Alice Jones
  1. first_name ← Alice, last_name ← Lee, full_name ← Alice Lee, greeting ← Hello, Alice Lee!

    1first_name→ Alice = "Alice"2last_name→ Lee = "Lee"34# Using + operator5full_name→ Alice Lee = first_nameAlice + " " + last_nameLee6print("Full name: " + full_nameAlice Lee)78# Using f-string (preferred)9greeting→ Hello, Alice Lee! = f"Hello, {first_nameAlice} {last_nameLee}!"10print(greetingHello, Alice Lee!)1112# Using .join()13parts→ ['Alice', 'Lee'] = [first_nameAlice, last_nameLee]14joined→ Alice Lee = " ".join(parts['Alice', 'Lee'])15print(f"Joined: {joinedAlice Lee}")
    outputFull name: Alice Lee
    Hello, Alice Lee!
    Joined: Alice Lee
f-string Formatted string: `f"Hello, {name}!"` - variables inside `{}`

Get string length

Find out how many characters are in a string.

word
length.py
Replay: real traced execution (multi-file project)
word = "Hello"
sentence = "Hello World"

print(f"'{word}' has {len(word)} characters")
print(f"'{sentence}' has {len(sentence)} characters")

# Empty string has length 0
empty = ""
print(f"Empty string length: {len(empty)}")
word = "Programming"
sentence = "Hello World"

print(f"'{word}' has {len(word)} characters")
print(f"'{sentence}' has {len(sentence)} characters")

# Empty string has length 0
empty = ""
print(f"Empty string length: {len(empty)}")
word = "Hi"
sentence = "Hello World"

print(f"'{word}' has {len(word)} characters")
print(f"'{sentence}' has {len(sentence)} characters")

# Empty string has length 0
empty = ""
print(f"Empty string length: {len(empty)}")
  1. word ← Hello, sentence ← Hello World, empty ← (empty)

    1word→ Hello = "Hello"     #@word="Programming", "Hi"2sentence→ Hello World = "Hello World"34print(f"'{wordHello}' has {len(word)} characters")5print(f"'{sentenceHello World}' has {len(sentence)} characters")67# Empty string has length 08empty→ (empty) = ""9print(f"Empty string length: {len(empty(empty))}")
    output'Hello' has 5 characters
    'Hello World' has 11 characters
    Empty string length: 0
  1. word ← Programming, sentence ← Hello World, empty ← (empty)

    1word→ Programming = "Programming"2sentence→ Hello World = "Hello World"34print(f"'{wordProgramming}' has {len(word)} characters")5print(f"'{sentenceHello World}' has {len(sentence)} characters")67# Empty string has length 08empty→ (empty) = ""9print(f"Empty string length: {len(empty(empty))}")
    output'Programming' has 11 characters
    'Hello World' has 11 characters
    Empty string length: 0
  1. word ← Hi, sentence ← Hello World, empty ← (empty)

    1word→ Hi = "Hi"2sentence→ Hello World = "Hello World"34print(f"'{wordHi}' has {len(word)} characters")5print(f"'{sentenceHello World}' has {len(sentence)} characters")67# Empty string has length 08empty→ (empty) = ""9print(f"Empty string length: {len(empty(empty))}")
    output'Hi' has 2 characters
    'Hello World' has 11 characters
    Empty string length: 0
len Length function: `len("Hello")` → `5`

Compare two strings

Check if strings are equal using ==.

user_input
compare.py
Replay: real traced execution (multi-file project)
a = "hello"
b = "hello"
c = "Hello"  # different case

# Python == compares content directly
print(f"a == b: {a == b}")       # True
print(f"a == c: {a == c}")       # False (case matters)
print(f"a.lower() == c.lower(): {a.lower() == c.lower()}")  # True

# Comparing with user input
user_input = "yes"
if user_input.lower() == "yes":
    print("User agreed!")

# Other comparisons
print(f"'apple' < 'banana': {'apple' < 'banana'}")  # alphabetical
print(f"'a' in 'cat': {'a' in 'cat'}")              # contains
a = "hello"
b = "hello"
c = "Hello"  # different case

# Python == compares content directly
print(f"a == b: {a == b}")       # True
print(f"a == c: {a == c}")       # False (case matters)
print(f"a.lower() == c.lower(): {a.lower() == c.lower()}")  # True

# Comparing with user input
user_input = "no"
if user_input.lower() == "yes":
    print("User agreed!")

# Other comparisons
print(f"'apple' < 'banana': {'apple' < 'banana'}")  # alphabetical
print(f"'a' in 'cat': {'a' in 'cat'}")              # contains
a = "hello"
b = "hello"
c = "Hello"  # different case

# Python == compares content directly
print(f"a == b: {a == b}")       # True
print(f"a == c: {a == c}")       # False (case matters)
print(f"a.lower() == c.lower(): {a.lower() == c.lower()}")  # True

# Comparing with user input
user_input = "YES"
if user_input.lower() == "yes":
    print("User agreed!")

# Other comparisons
print(f"'apple' < 'banana': {'apple' < 'banana'}")  # alphabetical
print(f"'a' in 'cat': {'a' in 'cat'}")              # contains
  1. a ← hello, b ← hello, c ← Hello, user_input ← yes

    1a→ hello = "hello"2b→ hello = "hello"3c→ Hello = "Hello"  # different case45# Python == compares content directly6print(f"a == b: {ahello == bhello}")       # True7print(f"a == c: {ahello == cHello}")       # False (case matters)8print(f"a.lower() == c.lower(): {ahello.lower() == cHello.lower()}")  # True910# Comparing with user input11user_input→ yes = "yes"   #@user_input="no", "YES"12if user_input.lower() == "yes":
    outputa == b: True
    a == c: False
    a.lower() == c.lower(): True
  2. if user_input.lower() == "yes":

    11user_input = "yes"   #@user_input="no", "YES"12if user_inputyes.lower() == "yes":13    print("User agreed!")
    outputUser agreed!
  3. print(f"'apple' < 'banana': {'apple' < 'banana'}") # alphabetical

    15# Other comparisons16print(f"'apple' < 'banana': {'apple' < 'banana'}")  # alphabetical17print(f"'a' in 'cat': {'a' in 'cat'}")              # contains
    output'apple' < 'banana': True
    'a' in 'cat': True
  1. a ← hello, b ← hello, c ← Hello, user_input ← no

    1a→ hello = "hello"2b→ hello = "hello"3c→ Hello = "Hello"  # different case45# Python == compares content directly6print(f"a == b: {ahello == bhello}")       # True7print(f"a == c: {ahello == cHello}")       # False (case matters)8print(f"a.lower() == c.lower(): {ahello.lower() == cHello.lower()}")  # True910# Comparing with user input11user_input→ no = "no"12if user_input.lower() == "yes":13    print("User agreed!")1415# Other comparisons16print(f"'apple' < 'banana': {'apple' < 'banana'}")  # alphabetical17print(f"'a' in 'cat': {'a' in 'cat'}")              # contains
    outputa == b: True
    a == c: False
    a.lower() == c.lower(): True
    'apple' < 'banana': True
    'a' in 'cat': True
  1. a ← hello, b ← hello, c ← Hello, user_input ← YES

    1a→ hello = "hello"2b→ hello = "hello"3c→ Hello = "Hello"  # different case45# Python == compares content directly6print(f"a == b: {ahello == bhello}")       # True7print(f"a == c: {ahello == cHello}")       # False (case matters)8print(f"a.lower() == c.lower(): {ahello.lower() == cHello.lower()}")  # True910# Comparing with user input11user_input→ YES = "YES"12if user_input.lower() == "yes":
    outputa == b: True
    a == c: False
    a.lower() == c.lower(): True
  2. if user_input.lower() == "yes":

    11user_input = "YES"12if user_inputYES.lower() == "yes":13    print("User agreed!")
    outputUser agreed!
  3. print(f"'apple' < 'banana': {'apple' < 'banana'}") # alphabetical

    15# Other comparisons16print(f"'apple' < 'banana': {'apple' < 'banana'}")  # alphabetical17print(f"'a' in 'cat': {'a' in 'cat'}")              # contains
    output'apple' < 'banana': True
    'a' in 'cat': True

Unlike Java, Python's == compares content directly. Simple and intuitive.

Access character by index

Get individual characters from a string by their position.

word
index.py
Replay: real traced execution (multi-file project)
word = "Hello"

# Index:    0  1  2  3  4
# Chars:    H  e  l  l  o
# Neg:     -5 -4 -3 -2 -1

first = word[0]
last = word[-1]      # Negative index = from end

print(f"Word: {word}")
print(f"First character: {first}")
print(f"Last character: {last}")
print(f"Second to last: {word[-2]}")

# Print all characters with their indices
for i, char in enumerate(word):
    print(f"Index {i}: {char}")
word = "World"

# Index:    0  1  2  3  4
# Chars:    H  e  l  l  o
# Neg:     -5 -4 -3 -2 -1

first = word[0]
last = word[-1]      # Negative index = from end

print(f"Word: {word}")
print(f"First character: {first}")
print(f"Last character: {last}")
print(f"Second to last: {word[-2]}")

# Print all characters with their indices
for i, char in enumerate(word):
    print(f"Index {i}: {char}")
word = "Python"

# Index:    0  1  2  3  4
# Chars:    H  e  l  l  o
# Neg:     -5 -4 -3 -2 -1

first = word[0]
last = word[-1]      # Negative index = from end

print(f"Word: {word}")
print(f"First character: {first}")
print(f"Last character: {last}")
print(f"Second to last: {word[-2]}")

# Print all characters with their indices
for i, char in enumerate(word):
    print(f"Index {i}: {char}")
  1. word ← Hello, first ← H, last ← o

    1word→ Hello = "Hello"  #@word="World", "Python"23# Index:    0  1  2  3  44# Chars:    H  e  l  l  o5# Neg:     -5 -4 -3 -2 -167first→ H = word[0]H8last→ o = word[-1]o      # Negative index = from end910print(f"Word: {wordHello}")11print(f"First character: {firstH}")12print(f"Last character: {lasto}")13print(f"Second to last: {word[-2]l}")
    outputWord: Hello
    First character: H
    Last character: o
    Second to last: l
  2. for i, char in enumerate(word):

    pass 1 of 5
    15# Print all characters with their indices16for i0, charH in enumerate(wordHello):17    print(f"Index {i0}: {charH}")
    outputIndex 0: H
    All 5 passes — pass 1 is the card above
    passichar
    10H
    21e
    32l
    43l
    54o
  1. word ← World, first ← W, last ← d

    1word→ World = "World"23# Index:    0  1  2  3  44# Chars:    H  e  l  l  o5# Neg:     -5 -4 -3 -2 -167first→ W = word[0]W8last→ d = word[-1]d      # Negative index = from end910print(f"Word: {wordWorld}")11print(f"First character: {firstW}")12print(f"Last character: {lastd}")13print(f"Second to last: {word[-2]l}")
    outputWord: World
    First character: W
    Last character: d
    Second to last: l
  2. for i, char in enumerate(word):

    pass 1 of 5
    15# Print all characters with their indices16for i0, charW in enumerate(wordWorld):17    print(f"Index {i0}: {charW}")
    outputIndex 0: W
    All 5 passes — pass 1 is the card above
    passichar
    10W
    21o
    32r
    43l
    54d
  1. word ← Python, first ← P, last ← n

    1word→ Python = "Python"23# Index:    0  1  2  3  44# Chars:    H  e  l  l  o5# Neg:     -5 -4 -3 -2 -167first→ P = word[0]P8last→ n = word[-1]n      # Negative index = from end910print(f"Word: {wordPython}")11print(f"First character: {firstP}")12print(f"Last character: {lastn}")13print(f"Second to last: {word[-2]o}")
    outputWord: Python
    First character: P
    Last character: n
    Second to last: o
  2. for i, char in enumerate(word):

    pass 1 of 6
    15# Print all characters with their indices16for i0, charP in enumerate(wordPython):17    print(f"Index {i0}: {charP}")
    outputIndex 0: P
    All 6 passes — pass 1 is the card above
    passichar
    10P
    21y
    32t
    43h
    54o
    65n

Python supports negative indices: -1 is the last character, -2 is second to last.

See String Positions

A string is a fixed sequence of character slots. These diagrams pin the exact word = "Hello" indexing example.

Positive and negative indices for HelloPositive and negative indices for Helloslot01234charHellonegative-5-4-3-2-1
Positive indices count from the left: `word[0]` is `H`. Negative indices count from the right: `word[-1]` is `o`.
Index expressions select one slotIndex expressions select one slotword="Hello"word[0]Hword[-1]oword[-2]l
`word[0]` selects `H`, `word[-1]` selects `o`, and `word[-2]` selects the second-to-last character `l`.
indexing Get character: `"Hello"[0]` → `'H'`, `"Hello"[-1]` → `'o'`

Exercise: special.py

Explore special strings: empty string, escape sequences, raw strings, multiline