Skip to content

Python Strings

A string (str) Immutable is a sequence of characters. Strings are how Python represents text, and they support indexing, slicing, looping, and a large set of built-in methods.

TaskSyntaxExample
Create'text', "text", '''text'''name = 'Sam'
Lengthlen(s)len('hello') gives 5
Indexs[i]'hello'[1] gives 'e'
Slices[start:stop:step]'hello'[1:4] gives 'ell'
Join+, join()'a' + 'b' gives 'ab'
Repeat*'ab' * 3 gives 'ababab'
Formatf'{value}'f'Age: {26}' gives 'Age: 26'
Searchin, find()'ell' in 'hello' gives True
Transform.upper(), .strip(), .replace()' hi '.strip() gives 'hi'

Single and double quotes behave identically. Choose whichever lets you avoid escaping.

quotes.py
a = 'Hello'
b = "World"
c = "It's a sunny day" # Single quote inside double quotes
d = 'She said, "Hello World!"' # Double quotes inside single quotes
e = 'It\'s' # Backslash escape
empty = '' # The empty string

A backslash gives the next character a special meaning.

SequenceMeaning
\nNew line
\tTab
\\A literal backslash
\'A literal single quote
\"A literal double quote
escapes.py
print('Line 1\nLine 2')
# Line 1
# Line 2
print('Name:\tSam') # Name: Sam

Prefix a string with r to turn off escape processing. This is useful for file paths and regular expressions.

raw_strings.py
print('C:\new\table') # Broken: \n and \t are interpreted as escapes
print(r'C:\new\table') # C:\new\table

Triple quotes (''' or """) let a string span several lines, preserving the layout exactly as written.

multiline.py
poem = """Roses are red,
Violets are blue."""
print(poem)
# Roses are red,
# Violets are blue.

  • len(s) returns the number of characters.
  • Zero-based indexing: positions run from 0 to len(s) - 1, so s[0] is the first character.
  • Negative indexing counts from the right: s[-1] is the last character and s[-2] is the second to last.
Index positions for 'Hello world'
H e l l o w o r l d
0 1 2 3 4 5 6 7 8 9 10
-11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1
indexing.py
my_str = 'Hello world'
print(len(my_str)) # 11
print(my_str[0]) # 'H'
print(my_str[-1]) # 'd'
print(my_str[20]) # IndexError: string index out of range

Strings cannot be changed in place. You can point a variable at a new string, but you cannot overwrite individual characters.

immutability.py
greeting = 'hello'
greeting = 'Hello' # Fine: the name now refers to a new string
greeting[0] = 'J' # TypeError: 'str' object does not support item assignment

To “modify” a string, build a new one:

modify_by_rebuilding.py
greeting = 'hello'
new_greeting = 'J' + greeting[1:] # 'Jello'
print(new_greeting)

Extract part of a string with string[start:stop:step].

  • stop is excluded. The slice runs up to, but not including, that index.
  • Defaults: omitting start means 0, omitting stop means the end, and omitting step means 1.
  • A negative step walks backward, so [::-1] reverses the string.
  • Out-of-range slices never raise errors. Python simply stops at the edges.
ExpressionResult for 'Hello world'
text[1:4]'ell'
text[:5]'Hello'
text[6:]'world'
text[-5:]'world'
text[:-6]'Hello'
text[::2]'Hlowrd'
text[::-1]'dlrow olleH'
text[:]'Hello world' (a full copy)
text[20:]'' (empty, no error)

OperationExampleResult
Concatenation (+)'A' + ' ' + 'B''A B'
Augmented assignment (+=)s += '!'Appends and reassigns
Repetition (*)'-' * 10'----------'
Conversion (str())str(26)'26'
combining.py
name = 'John Doe'
age = 26
print(name + ' ' + str(age)) # 'John Doe 26'
print(name + ' ' + age) # TypeError: can only concatenate str (not "int") to str
message = 'Hello'
message += '!' # 'Hello!'
print('=' * 20) # '===================='

Prefix a string with f and place expressions inside {}. f-strings convert non-string values automatically and can evaluate any expression.

f_strings.py
name = 'John'
age = 26
print(f'{name} is {age} years old') # John is 26 years old
print(f'Summing: {5} + {10} = {5 + 10}') # Summing: 5 + 10 = 15
print(f'Shout: {name.upper()}') # Shout: JOHN
print(f'{age = }') # age = 26 (debugging aid, Python 3.8+)

Add : after the expression to control how the value is displayed.

SpecifierExampleResult
.2ff'{3.14159:.2f}''3.14'
,f'{1234567:,}''1,234,567'
.1%f'{0.256:.1%}''25.6%'
05df'{42:05d}''00042'
>8f"{'hi':>8}"' hi' (right-aligned)
<8f"{'hi':<8}"'hi ' (left-aligned)
^8f"{'hi':^8}"' hi ' (centered)
!rf'{name!r}'"'John'" (shows the repr)
print(f'{name} is {age}')

The clearest and fastest option. Use this by default.


in and not in test whether one string appears inside another and return a Boolean.

membership_and_comparison.py
sentence = 'The quick brown fox'
print('quick' in sentence) # True
print('slow' not in sentence) # True
print('Quick' in sentence) # False, matching is case-sensitive
print('apple' == 'Apple') # False
print('apple' < 'banana') # True, compared alphabetically by character code
print('Zebra' < 'apple') # True, all uppercase letters sort before lowercase

Call a method with dot notation: variable.method(). Remember that every method returns a new value.

MethodResultExample
upper()All uppercase'hi'.upper() gives 'HI'
lower()All lowercase'HI'.lower() gives 'hi'
capitalize()First character upper, the rest lower'hELLO'.capitalize() gives 'Hello'
title()First letter of every word upper'hello world'.title() gives 'Hello World'
swapcase()Inverts the case of every letter'Hi'.swapcase() gives 'hI'
MethodResultExample
strip()Removes leading and trailing whitespace' hi '.strip() gives 'hi'
lstrip() / rstrip()Strips only the left or right side' hi '.rstrip() gives ' hi'
strip(chars)Removes any of the listed characters from both ends'!!hi!!'.strip('!') gives 'hi'
replace(old, new)Replaces every occurrence'a-b-c'.replace('-', '/') gives 'a/b/c'
replace(old, new, n)Replaces only the first n occurrences'a-b-c'.replace('-', '/', 1) gives 'a/b-c'
removeprefix(p) 3.9+Removes a prefix if present'unhappy'.removeprefix('un') gives 'happy'
removesuffix(s) 3.9+Removes a suffix if present'report.txt'.removesuffix('.txt') gives 'report'
MethodResultExample
find(sub)Index of the first match, or -1 if absent'hello'.find('l') gives 2
index(sub)Like find(), but raises ValueError if absent'hello'.index('z') raises an error
rfind(sub)Index of the last match, or -1'hello'.rfind('l') gives 3
count(sub)Non-overlapping occurrences'banana'.count('an') gives 2
startswith(p)Whether the string begins with p'hello'.startswith('he') gives True
endswith(s)Whether the string ends with s'hello'.endswith('lo') gives True
MethodResultExample
split()Splits on any whitespace, ignoring extra spaces'a b c'.split() gives ['a', 'b', 'c']
split(sep)Splits at each separator'a,b,,c'.split(',') gives ['a', 'b', '', 'c']
split(sep, n)Splits at most n times'a,b,c'.split(',', 1) gives ['a', 'b,c']
splitlines()Splits at line breaks'a\nb'.splitlines() gives ['a', 'b']
partition(sep)Splits into (before, sep, after) at the first match'key=value'.partition('=') gives ('key', '=', 'value')
join(items)Glues strings together using the host string as separator'-'.join(['a', 'b']) gives 'a-b'
split_and_join.py
words = 'one two three'.split() # ['one', 'two', 'three']
print('-'.join(words)) # 'one-two-three'
print('-'.join([1, 2, 3])) # TypeError: items must be strings
print('-'.join(str(n) for n in [1, 2, 3])) # '1-2-3'

Each of these returns True or False. All return False for an empty string.

MethodTrue when the string…Example
isdigit()contains only digits'42'.isdigit() is True, '-5'.isdigit() is False
isalpha()contains only letters'abc'.isalpha() is True
isalnum()contains only letters and digits'abc123'.isalnum() is True
isspace()contains only whitespace' '.isspace() is True
isupper()has at least one letter and all letters are uppercase'HELLO'.isupper() is True
islower()has at least one letter and all letters are lowercase'hello'.islower() is True
MethodExampleResult
zfill(width)'7'.zfill(3)'007'
center(width, fill)'hi'.center(8, '*')'***hi***'
ljust(width, fill)'hi'.ljust(5, '.')'hi...'
rjust(width, fill)'hi'.rjust(5, '.')'...hi'

Because each method returns a string, you can chain them left to right.

chaining.py
raw_text = ' Hello World '
print(raw_text.strip().lower().replace(' ', '-')) # 'hello-world'

A string is a sequence, so you can iterate over its characters directly.

iteration.py
for char in 'abc':
print(char) # a, b, c
for index, char in enumerate('abc'):
print(index, char) # 0 a, 1 b, 2 c

  1. Normalize the input. Use strip(), split(), and lower() or title() to remove noise and unify the case.

  2. Validate it. Use in, startswith(), isdigit(), or isalpha() to confirm the content is what you expect.

  3. Transform it. Use replace(), slicing, and join() to reshape the text.

  4. Present it. Use an f-string to format the final output.

clean_name.py
raw_name = ' jOHN dOE '
clean_name = ' '.join(raw_name.split()).title()
print(f'Hello, {clean_name}!') # Hello, John Doe!
palindrome.py
def is_palindrome(text):
cleaned = ''.join(ch.lower() for ch in text if ch.isalnum())
return cleaned == cleaned[::-1]
print(is_palindrome('A man, a plan, a canal: Panama')) # True
print(is_palindrome('Python')) # False

MistakeProblemFix
s[0] = 'H'TypeError, strings are immutables = 'H' + s[1:]
s.upper() with no assignmentThe new string is discardeds = s.upper()
'Age: ' + 26TypeError, cannot add str and intf'Age: {26}' or 'Age: ' + str(26)
s[len(s)]IndexError, the last index is len(s) - 1s[-1]
'-'.join([1, 2])TypeError, join needs strings'-'.join(map(str, [1, 2]))
s.strip('abc') expecting a substringstrip removes any of those characters, not the exact textUse removeprefix() or removesuffix()
'hello' in 'Hello World'Matching is case-sensitiveCompare .lower() versions
"they're".title()Gives "They'Re"Use string.capwords() for simple cases
'42'.isdigit() to validate numbersRejects negatives and decimalsTry int() or float() in a try / except
  1. Pick the quote style that avoids escaping, and stay consistent within a project.
  2. Use f-strings for formatting instead of + or %.
  3. Build text from many pieces with join(), not repeated concatenation.
  4. Remember that strings are immutable, and always capture the result of a method.
  5. Prefer slicing over manual index arithmetic, and use negative indices to count from the end.
  6. Normalize with strip() and lower() before comparing user input.
  7. Use find() when absence is acceptable and index() when it should be an error.
  8. Use raw strings (r'...') for Windows paths and regular expressions.