Lists and strings are two of the most frequently used data types in Python. Both are sequences — ordered collections of items that support indexing, slicing, and iteration. Strings are sequences of characters; lists are sequences of any values. Understanding both in depth, along with their built-in methods, is essential for writing practical Python code.
Lists
A list is an ordered, mutable collection of items. Items can be of any type — including mixed types — and the list can grow or shrink after creation.
fruits = ["apple", "banana", "cherry"]
mixed = [1, "hello", True, 3.14, None]
empty = []
nested = [[1, 2], [3, 4], [5, 6]]
Accessing Items — Indexing
Lists are zero-indexed. Negative indices count from the end:
fruits = ["apple", "banana", "cherry"]
fruits[0] # "apple"
fruits[1] # "banana"
fruits[-1] # "cherry" — last item
fruits[-2] # "banana" — second to last
Accessing a Range — Slicing
fruits = ["apple", "banana", "cherry", "date", "elderberry"]
fruits[1:4] # ["banana", "cherry", "date"] — index 1 up to (not including) 4
fruits[:3] # ["apple", "banana", "cherry"] — from start to index 3
fruits[2:] # ["cherry", "date", "elderberry"] — from index 2 to end
fruits[::2] # ["apple", "cherry", "elderberry"] — every second item
fruits[::-1] # ["elderberry", "date", "cherry", "banana", "apple"] — reversed
Slicing never raises an error for out-of-range indices — it simply returns what is available.
Modifying Items
Lists are mutable — you can change items after creation:
fruits = ["apple", "banana", "cherry"]
fruits[1] = "blueberry"
print(fruits) # ["apple", "blueberry", "cherry"]
List Methods
Adding Items
fruits = ["apple", "banana"]
fruits.append("cherry") # Add to the end
# ["apple", "banana", "cherry"]
fruits.insert(1, "blueberry") # Insert at index 1
# ["apple", "blueberry", "banana", "cherry"]
fruits.extend(["date", "elderberry"]) # Add all items from another list
# ["apple", "blueberry", "banana", "cherry", "date", "elderberry"]
Removing Items
fruits = ["apple", "banana", "cherry", "banana"]
fruits.remove("banana") # Removes the first occurrence
# ["apple", "cherry", "banana"]
fruits.pop() # Removes and returns the last item
# Returns "banana", list becomes ["apple", "cherry"]
fruits.pop(0) # Removes and returns item at index 0
# Returns "apple", list becomes ["cherry"]
fruits.clear() # Removes all items
# []
Searching
fruits = ["apple", "banana", "cherry", "banana"]
fruits.index("banana") # 1 — index of first occurrence
fruits.count("banana") # 2 — how many times it appears
"cherry" in fruits # True — membership check
Sorting and Reversing
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
numbers.sort() # Sorts in place — ascending
# [1, 1, 2, 3, 4, 5, 6, 9]
numbers.sort(reverse=True) # Sorts in place — descending
# [9, 6, 5, 4, 3, 2, 1, 1]
numbers.reverse() # Reverses in place
sort() modifies the list in place and returns None. sorted() returns a new sorted list and leaves the original unchanged:
original = [3, 1, 4, 1, 5]
new = sorted(original) # New sorted list
print(original) # [3, 1, 4, 1, 5] — unchanged
print(new) # [1, 1, 3, 4, 5]
Copying a List
original = [1, 2, 3]
copy = original.copy() # Shallow copy
copy2 = original[:] # Also a shallow copy using slicing
copy3 = list(original) # Also a shallow copy
Important: Assigning a list to a new variable does not copy it — both variables point to the same list:
a = [1, 2, 3] b = a # b is NOT a copy — it is the same list b.append(4) print(a) # [1, 2, 3, 4] — a was also modified
Other Useful Methods
fruits = ["apple", "banana", "cherry"]
len(fruits) # 3 — number of items
min([3, 1, 4]) # 1 — smallest value
max([3, 1, 4]) # 4 — largest value
sum([1, 2, 3, 4]) # 10 — sum of all items
list(reversed(fruits)) # ["cherry", "banana", "apple"]
List Comprehensions
List comprehensions are Python's concise, readable way to create a new list by transforming or filtering an existing iterable. They are one of Python's most distinctly Pythonic features.
# Basic syntax: [expression for item in iterable]
squares = [x ** 2 for x in range(1, 6)]
print(squares) # [1, 4, 9, 16, 25]
With a condition (filter):
# [expression for item in iterable if condition]
evens = [x for x in range(10) if x % 2 == 0]
print(evens) # [0, 2, 4, 6, 8]
Transforming a list of strings:
fruits = ["apple", "banana", "cherry"]
upper = [fruit.upper() for fruit in fruits]
print(upper) # ["APPLE", "BANANA", "CHERRY"]
The equivalent using a for loop is more verbose:
upper = []
for fruit in fruits:
upper.append(fruit.upper())
List comprehensions are preferred for simple transformations. For complex logic, a regular loop is clearer.
Strings
Strings are immutable sequences of characters. Every string method returns a new string — the original is never modified.
name = "Wariz"
name[0] = "w" # ❌ TypeError — strings are immutable
Indexing and Slicing
Strings support the same indexing and slicing syntax as lists:
name = "Wariz"
name[0] # "W"
name[-1] # "z"
name[1:4] # "ari"
name[::-1] # "ziraW" — reversed
String Methods
Case Methods
text = "hello world"
text.upper() # "HELLO WORLD"
text.lower() # "hello world"
text.title() # "Hello World" — capitalises first letter of each word
text.capitalize() # "Hello world" — capitalises only the first letter
text.swapcase() # "HELLO WORLD" → "hello world" and vice versa
Whitespace Methods
text = " hello world "
text.strip() # "hello world" — removes leading and trailing whitespace
text.lstrip() # "hello world " — removes leading only
text.rstrip() # " hello world" — removes trailing only
Search and Check Methods
text = "Hello, World!"
text.find("World") # 7 — index of first occurrence (-1 if not found)
text.index("World") # 7 — same, but raises ValueError if not found
text.rfind("l") # 10 — last occurrence
text.count("l") # 3 — number of occurrences
text.startswith("Hello") # True
text.endswith("!") # True
"hello" in text # False — case-sensitive
"Hello" in text # True
Replace and Split
text = "Hello, World!"
text.replace("World", "Python") # "Hello, Python!"
text.replace("l", "r", 2) # Replace first 2 occurrences only
sentence = "apple,banana,cherry"
sentence.split(",") # ["apple", "banana", "cherry"]
"hello world".split() # ["hello", "world"] — splits on whitespace
"hello world".split(" ", 1) # ["hello", "world"] — max 1 split
Join
join() is the reverse of split() — it combines a list of strings into one:
words = ["apple", "banana", "cherry"]
", ".join(words) # "apple, banana, cherry"
" | ".join(words) # "apple | banana | cherry"
"".join(["a", "b", "c"]) # "abc"
Check Methods
"hello".isalpha() # True — all alphabetic characters
"hello123".isalnum() # True — all alphanumeric
"12345".isdigit() # True — all digits
" ".isspace() # True — all whitespace
"Hello World".istitle() # True — title case
"HELLO".isupper() # True — all uppercase
"hello".islower() # True — all lowercase
Formatting Methods
"hello".center(11) # " hello " — centred in 11 characters
"hello".ljust(10) # "hello " — left-aligned, padded
"hello".rjust(10) # " hello" — right-aligned, padded
"hello".center(11, "-") # "---hello---" — with fill character
"42".zfill(5) # "00042" — zero-padded
f-strings vs. .format()
f-strings are the modern, preferred approach:
name = "Wariz"
age = 20
# f-string (Python 3.6+) — preferred
f"Hello, {name}. You are {age} years old."
# .format() — older approach, still valid
"Hello, {}. You are {} years old.".format(name, age)
"Hello, {name}. You are {age} years old.".format(name=name, age=age)
Useful Built-in Functions for Sequences
These work on both lists and strings:
fruits = ["apple", "banana", "cherry"]
len(fruits) # 3 — length
min(fruits) # "apple" — lexicographically smallest
max(fruits) # "cherry" — lexicographically largest
sorted(fruits) # New sorted list
list(reversed(fruits)) # ["cherry", "banana", "apple"]
enumerate(fruits) # Pairs of (index, value)
Summary
List Methods
| Method | What It Does |
|---|---|
append(item) | Adds item to the end |
insert(i, item) | Inserts item at index i |
extend(iterable) | Adds all items from iterable |
remove(item) | Removes first occurrence of item |
pop(i) | Removes and returns item at index i (default: last) |
clear() | Removes all items |
index(item) | Returns index of first occurrence |
count(item) | Counts occurrences |
sort() | Sorts in place |
reverse() | Reverses in place |
copy() | Returns a shallow copy |
String Methods
| Method | What It Does |
|---|---|
upper() / lower() | Changes case |
title() / capitalize() | Capitalises words or first letter |
strip() / lstrip() / rstrip() | Removes whitespace |
find(s) / index(s) | Finds substring position |
count(s) | Counts occurrences of substring |
startswith(s) / endswith(s) | Checks start or end |
replace(old, new) | Replaces substring |
split(sep) | Splits into a list |
join(iterable) | Joins list into a string |
isalpha() / isdigit() / isalnum() | Checks character types |
zfill(n) | Zero-pads to length n |