Strings¶
A string is text — a sequence of characters. In Python you can use single or double quotes.
Creating strings¶
Accessing characters by index¶
Strings are indexed from 0. Negative indices count from the end.
word = "Python"
print(word[0]) # 'P' — first char
print(word[1]) # 'y'
print(word[-1]) # 'n' — last char
print(word[-2]) # 'o'
print(len(word)) # 6 — length
Slicing — substrings¶
string[start:stop] gives you characters from start (inclusive) to stop (exclusive).
word = "Python"
print(word[0:3]) # 'Pyt'
print(word[2:5]) # 'tho'
print(word[:3]) # 'Pyt' — from start
print(word[3:]) # 'hon' — to end
print(word[-3:]) # 'hon' — last 3
print(word[::2]) # 'Pto' — every 2nd char
print(word[::-1]) # 'nohtyP' — reversed!
Strings are immutable¶
You cannot change a character in place:
word = "Python"
# word[0] = "J" # ← TypeError: strings are immutable
# Instead, create a new string
new_word = "J" + word[1:]
print(new_word) # 'Jython'
Common string methods¶
s = " Hello, World! "
print(s.lower()) # ' hello, world! '
print(s.upper()) # ' HELLO, WORLD! '
print(s.strip()) # 'Hello, World!' — removes outer whitespace
print(s.lstrip()) # left strip only
print(s.rstrip()) # right strip only
print(s.replace("World", "Python")) # ' Hello, Python! '
print(s.title()) # ' Hello, World! '
print(s.capitalize()) # ' hello, world! '
print(s.swapcase()) # ' hELLO, wORLD! '
Searching in strings¶
s = "Python is awesome and Python is easy"
print("Python" in s) # True
print("Java" in s) # False
print(s.find("is")) # 7 — first occurrence
print(s.find("missing")) # -1 — not found
print(s.index("is")) # 7 — like find but raises if missing
print(s.count("Python")) # 2 — number of occurrences
print(s.startswith("Py")) # True
print(s.endswith("easy")) # True
Splitting and joining¶
# split — string → list
csv = "apple,banana,cherry"
fruits = csv.split(",")
print(fruits) # ['apple', 'banana', 'cherry']
# split by whitespace (default)
sentence = "Python is great"
words = sentence.split()
print(words) # ['Python', 'is', 'great']
# join — list → string
parts = ["2025", "01", "31"]
date = "-".join(parts)
print(date) # '2025-01-31'
# Lines
text = "line1\nline2\nline3"
print(text.splitlines()) # ['line1', 'line2', 'line3']
Checking string content¶
print("abc123".isalnum()) # True — letters or digits
print("abc".isalpha()) # True — only letters
print("123".isdigit()) # True — only digits
print("hello".islower()) # True
print("HELLO".isupper()) # True
print(" ".isspace()) # True
print("Hello World".istitle()) # True
String formatting — f-strings (modern)¶
name = "Alice"
age = 25
balance = 1234.5678
print(f"{name} is {age}") # Alice is 25
print(f"Balance: ${balance:.2f}") # Balance: $1234.57
print(f"Padded: {age:>5}") # right-aligned in 5 chars
print(f"Filled: {age:0>5}") # zero-padded: 00025
print(f"Centered: {name:^10}") # centered in 10 chars
print(f"Binary: {255:b}") # 11111111
print(f"Hex: {255:x}") # ff
print(f"Percent: {0.875:.1%}") # 87.5%
print(f"Scientific:{12345:.2e}") # 1.23e+04
Escape characters¶
Some special characters need a backslash:
print("Hello\nWorld") # \n = newline
print("Col1\tCol2\tCol3") # \t = tab
print("She said \"hi\"") # \" inside double quotes
print("Path: C:\\Users") # \\ = literal backslash
# Raw string — backslashes are literal
print(r"Path: C:\Users\Alice") # no escape needed
Repeating + concatenating¶
print("ha" * 3) # 'hahaha'
print("=" * 20) # '====================='
print("Hello, " + "World") # 'Hello, World'
Iterating over a string¶
for letter in "Python":
print(letter)
# Count vowels
text = "Hello, World!"
vowels = sum(1 for ch in text.lower() if ch in "aeiou")
print(f"{vowels} vowels")
Mini-project — Palindrome checker¶
A palindrome reads the same forwards and backwards.
def is_palindrome(text):
clean = text.lower().replace(" ", "")
return clean == clean[::-1]
print(is_palindrome("racecar")) # True
print(is_palindrome("A man a plan a canal Panama")) # True
print(is_palindrome("python")) # False
Practice¶
Print 'hello, world' in all lowercase, no extra spaces
Expected: hello, world
Quiz — Quick check¶
What you remember
Q1. What does "banana".count("a") return?
-
1 -
2 -
3 -
"a"
Why:
countreturns the number of non-overlapping occurrences of the substring. "b-A-n-A-n-A" has threeas.
Q2. Which of these makes word lowercase in place?
-
word.lower() -
word = lower(word) - None of the above — strings are immutable; you must reassign with
word = word.lower() -
word.lowercase()
Why: Strings can't be mutated. Every "string method" returns a new string; you have to assign it back if you want the original variable to change.
Q3. What does "a,b,,c".split(",") produce?
-
["a", "b", "c"] -
["a", "b", "", "c"] -
["a,b,c"] -
["a", "b", "c", ""]
Why:
splitpreserves empty strings between consecutive delimiters. To drop empties, filter the result or usesplit()without an argument (which collapses whitespace).
Common doubts¶
Why does s[0] = 'x' give a TypeError?
Strings are immutable — you can't change them in place. Build a new string instead: s = 'x' + s[1:]. The same rule applies to tuples; lists and dicts are mutable.
Difference between find and index?
Both return the position of a substring. find returns -1 if not found; index raises ValueError. Use find when "not found" is expected; use index when you want a hard error to surface a bug.
When should I use an f-string vs .format()?
Always default to f-strings. They're faster, shorter, and the variable names appear right where they're used. The only place you can't use f-strings is when the template comes from elsewhere (config, database) — there you need .format(**values).
What's next¶
→ Lists