Python Lists & Methods
A list (list) Mutable is an ordered collection of items. Lists can hold any mix of types, can grow and shrink, and are the most commonly used data structure in Python.
At a Glance
Section titled “At a Glance”| Task | Syntax | Example |
|---|---|---|
| Create | [...], list(iterable) | list('Dev') gives ['D', 'e', 'v'] |
| Length | len(lst) | len([1, 2, 3]) gives 3 |
| Access | lst[i], lst[-1] | ['a', 'b'][-1] gives 'b' |
| Slice | lst[start:stop:step] | [1, 2, 3, 4][1:3] gives [2, 3] |
| Add one | .append(x), .insert(i, x) | lst.append(4) |
| Add many | .extend(iterable), + | lst.extend([4, 5]) |
| Remove | .remove(x), .pop(i), del lst[i] | lst.pop() |
| Search | x in lst, .index(x), .count(x) | 2 in [1, 2, 3] gives True |
| Sort | .sort(), sorted(lst) | sorted([3, 1, 2]) gives [1, 2, 3] |
| Build | [expr for x in iterable] | [n * 2 for n in range(3)] gives [0, 2, 4] |
Creating Lists
Section titled “Creating Lists”empty = []cities = ['London', 'Tokyo']mixed = [1, 'two', 3.0, [4, 5]] # Any types, even other listschars = list('Dev') # ['D', 'e', 'v']digits = list(range(5)) # [0, 1, 2, 3, 4]Basic Operations
Section titled “Basic Operations”nums = [10, 20, 30]
print(len(nums)) # 3print(nums[0]) # 10print(nums[-1]) # 30, negative indices count from the endnums[1] = 25 # Lists are mutable, so items can be replacedprint(nums) # [10, 25, 30]
print(30 in nums) # Trueprint([1, 2] + [3]) # [1, 2, 3], concatenation creates a new listprint([0] * 3) # [0, 0, 0], repetitionprint(min(nums), max(nums), sum(nums)) # 10 30 65Slicing
Section titled “Slicing”Extract part of a list with lst[start:stop:step]. As with strings, stop is excluded, omitted bounds default to the start or end, and a negative step walks backward. Slicing always returns a new list.
| Expression | Result for items = ['a', 'b', 'c', 'd', 'e'] |
|---|---|
items[1:4] | ['b', 'c', 'd'] |
items[:2] | ['a', 'b'] |
items[3:] | ['d', 'e'] |
items[-2:] | ['d', 'e'] |
items[::2] | ['a', 'c', 'e'] |
items[::-1] | ['e', 'd', 'c', 'b', 'a'] |
items[:] | ['a', 'b', 'c', 'd', 'e'] (a shallow copy) |
items[10:] | [] (out-of-range slices never raise errors) |
Slices can also be assigned to or deleted:
items = ['a', 'b', 'c', 'd', 'e']
items[1:3] = ['X'] # Replaces two items with oneprint(items) # ['a', 'X', 'd', 'e']
del items[1:3] # Deletes a rangeprint(items) # ['a', 'e']Adding Items
Section titled “Adding Items”| Method | Behavior | Complexity |
|---|---|---|
.append(x) | Adds x as a single item at the end | O(1) |
.extend(iterable) | Adds each item of the iterable at the end | O(k) |
.insert(i, x) | Inserts x at index i, shifting later items right | O(n) |
numbers = [1, 2, 3]extras = [4, 5]
numbers.append(extras) # [1, 2, 3, [4, 5]], nests the list as one item
numbers = [1, 2, 3]numbers.extend(extras) # [1, 2, 3, 4, 5], adds items individually
numbers.insert(2, 2.5) # [1, 2, 2.5, 3, 4, 5]
numbers += [6, 7] # [1, 2, 2.5, 3, 4, 5, 6, 7], same as extend()Removing Items
Section titled “Removing Items”| Method / Keyword | Behavior |
|---|---|
.pop() | Removes and returns the last item |
.pop(i) | Removes and returns the item at index i |
.remove(x) | Removes the first item equal to x |
del lst[i] | Deletes the item at i (or a slice) without returning it |
.clear() | Removes every item, leaving [] |
numbers = [10, 20, 30, 40, 50, 50]
numbers.remove(50) # [10, 20, 30, 40, 50], only the first match is removedremoved = numbers.pop(1) # removed is 20, list is [10, 30, 40, 50]last = numbers.pop() # last is 50, list is [10, 30, 40]del numbers[0] # [30, 40]numbers.clear() # []To remove every match, rebuild the list instead:
numbers = [10, 50, 20, 50]numbers = [n for n in numbers if n != 50] # [10, 20]Searching and Counting
Section titled “Searching and Counting”langs = ['Rust', 'Java', 'Python', 'Java']
print('Java' in langs) # Trueprint(langs.index('Java')) # 1, first occurrenceprint(langs.index('Java', 2)) # 3, start searching at index 2print(langs.count('Java')) # 2print(langs.index('Go')) # ValueError: 'Go' is not in listSorting and Reversing
Section titled “Sorting and Reversing”| Tool | Behavior | Returns |
|---|---|---|
lst.sort() | Sorts the list in place | None |
sorted(lst) | Builds a new sorted list, original untouched | A new list |
lst.reverse() | Reverses the list in place | None |
reversed(lst) | Iterates in reverse without changing the list | An iterator |
nums = [19, 2, 35, 1]nums.sort() # nums is now [1, 2, 19, 35]nums.sort(reverse=True) # nums is now [35, 19, 2, 1]Use when you no longer need the original order.
nums = [19, 2, 35, 1]result = sorted(nums) # [1, 2, 19, 35]print(nums) # [19, 2, 35, 1], unchangedUse when you need to keep the original, or when sorting any iterable (strings, tuples, sets).
Custom Sorting with key
Section titled “Custom Sorting with key”The key function is applied to each item, and the results decide the order.
words = ['banana', 'Cherry', 'apple']
print(sorted(words)) # ['Cherry', 'apple', 'banana'], uppercase sorts firstprint(sorted(words, key=str.lower)) # ['apple', 'banana', 'Cherry']print(sorted(words, key=len)) # ['apple', 'Cherry', 'banana']
people = [('Ann', 31), ('Bob', 25)]print(sorted(people, key=lambda p: p[1])) # [('Bob', 25), ('Ann', 31)]Copying and Aliasing
Section titled “Copying and Aliasing”Assigning a list to another name does not copy it. Both names refer to the same list.
a = [1, 2, 3]b = a # Alias: one list, two namesb.append(4)print(a) # [1, 2, 3, 4], a changed too
c = a.copy() # A genuine copy (also: a[:] or list(a))c.append(5)print(a) # [1, 2, 3, 4], unaffectedShallow vs. Deep Copies
Section titled “Shallow vs. Deep Copies”.copy() is shallow: it creates a new outer list, but any nested lists are still shared. Use copy.deepcopy() for full independence.
import copy
original = [1, 2, [3, 4]]
shallow = original.copy()shallow[2].append(5)print(original) # [1, 2, [3, 4, 5]], the inner list is shared
deep = copy.deepcopy(original)deep[2].append(6)print(original) # [1, 2, [3, 4, 5]], unchangedUnpacking
Section titled “Unpacking”Unpacking assigns list items to several variables in one statement.
point = [10, 20]x, y = point # x = 10, y = 20
first, *rest = [1, 2, 3, 4] # first = 1, rest = [2, 3, 4]*head, last = [1, 2, 3, 4] # head = [1, 2, 3], last = 4first, *middle, last = [1, 2, 3, 4, 5] # 1, [2, 3, 4], 5
a, b = 1, 2a, b = b, a # Swap without a temp variable
x, y = [1, 2, 3] # ValueError: too many values to unpack (expected 2)The starred name (*rest) collects “everything else” into a list and may appear once.
Looping Over Lists
Section titled “Looping Over Lists”langs = ['Rust', 'Java', 'Python']
for lang in langs: print(lang)
for index, lang in enumerate(langs, start=1): print(index, lang) # 1 Rust, 2 Java, 3 Python
names = ['Ann', 'Bob']scores = [90, 85]for name, score in zip(names, scores): print(name, score) # Ann 90, Bob 85Nested Lists
Section titled “Nested Lists”A list can contain other lists. Chain indices to reach inner items: lst[outer][inner].
dev = ['Alice', 25, ['Python', 'Rust', 'C++']]print(dev[2][1]) # 'Rust'
matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9],]print(matrix[1][2]) # 6, row 1, column 2
for row in matrix: for value in row: print(value, end=' ') # 1 2 3 4 5 6 7 8 9Building a Grid Correctly
Section titled “Building a Grid Correctly”Repetition copies references, so [[0] * 3] * 3 creates three names for one row. Use a comprehension to build independent rows.
bad = [[0] * 3] * 3bad[0][0] = 1print(bad) # [[1, 0, 0], [1, 0, 0], [1, 0, 0]], all rows changed
good = [[0] * 3 for _ in range(3)]good[0][0] = 1print(good) # [[1, 0, 0], [0, 0, 0], [0, 0, 0]]List Comprehensions
Section titled “List Comprehensions”A comprehension builds a new list from an iterable in a single expression.
# Traditional loopeven_numbers = []for num in range(21): if num % 2 == 0: even_numbers.append(num)
# Comprehension, same resulteven_numbers = [num for num in range(21) if num % 2 == 0]print(even_numbers) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]Choosing the Right Pattern
Section titled “Choosing the Right Pattern”| Goal | Pattern | Example |
|---|---|---|
| Transform each item | [expr for x in items] | [n ** 2 for n in range(1, 6)] gives [1, 4, 9, 16, 25] |
| Keep only some items | [expr for x in items if cond] | [n for n in range(10) if n > 6] gives [7, 8, 9] |
| Choose between two values | [a if cond else b for x in items] | ['Even' if n % 2 == 0 else 'Odd' for n in [1, 2]] gives ['Odd', 'Even'] |
| Flatten nested lists | [x for row in rows for x in row] | [x for row in [[1, 2], [3]] for x in row] gives [1, 2, 3] |
Conditional Values
Section titled “Conditional Values”numbers = [1, 2, 3, 4, 5]
result = [(num, 'Even') if num % 2 == 0 else (num, 'Odd') for num in numbers]print(result)# [(1, 'Odd'), (2, 'Even'), (3, 'Odd'), (4, 'Even'), (5, 'Odd')]Time Complexity
Section titled “Time Complexity”Big-O notation describes how an operation’s cost grows as the list size n grows.
O(1)(constant): the cost stays the same for 5 items or 5,000,000.O(n)(linear): the cost grows with the list, because Python may inspect every item.O(k): the cost depends on the number of items k being added or extracted.
| Operation | Complexity | Speed |
|---|---|---|
lst[i], len(lst) | O(1) | Fast |
.append(x), .pop() (last item) | O(1) | Fast |
.extend(iterable), slicing | O(k) | Proportional |
.insert(i, x), .pop(i), .remove(x), del lst[i] | O(n) | Linear |
x in lst, .index(x), .count(x) | O(n) | Linear |
.copy(), .reverse(), min(), max(), sum() | O(n) | Linear |
.sort(), sorted() | O(n log n) | Timsort |
Putting It Together
Section titled “Putting It Together”-
Clean. Filter out unwanted items and normalize the rest with a comprehension.
-
Deduplicate.
dict.fromkeys()removes duplicates while preserving order. Asetwould lose the order. -
Sort. Use
.sort()orsorted(), with akeywhen needed. -
Present. Use
', '.join(items)to turn the list into text.
raw = [' Banana', 'apple ', 'Cherry', 'apple', '']
cleaned = [item.strip().lower() for item in raw if item.strip()]print(cleaned) # ['banana', 'apple', 'cherry', 'apple']
unique = list(dict.fromkeys(cleaned))print(unique) # ['banana', 'apple', 'cherry']
unique.sort()print(', '.join(unique)) # apple, banana, cherryCommon Mistakes
Section titled “Common Mistakes”| Mistake | Problem | Fix |
|---|---|---|
nums = nums.sort() | .sort() returns None | nums.sort() or nums = sorted(nums) |
lst = lst.append(x) | .append() returns None | lst.append(x) |
b = a expecting a copy | Both names share one list | b = a.copy() |
[[0] * 3] * 3 | Rows are the same object | [[0] * 3 for _ in range(3)] |
Removing items inside a for loop | Items get skipped | Use a comprehension or loop over lst[:] |
.remove(x) / .index(x) on a missing value | ValueError | Check x in lst first |
.append([4, 5]) expecting two items | Adds one nested list | .extend([4, 5]) |
lst[len(lst)] | IndexError, the last index is len(lst) - 1 | lst[-1] |
def f(items=[]) | The default list is shared across calls | def f(items=None) then items = items or [] |
lst = lst + [x] in a loop | Builds a new list every time | lst.append(x) |
| Shallow copy of nested lists | Inner lists are still shared | copy.deepcopy(lst) |
Best Practices Checklist
Section titled “Best Practices Checklist”- Use
.append()for one item and.extend()for many. - Use
sorted()when you must keep the original order, and.sort()when you do not. - Copy deliberately:
.copy()for flat lists,copy.deepcopy()for nested ones. - Never modify a list while iterating over it. Build a new one instead.
- Use
enumerate()andzip()instead of manual index counters. - Use comprehensions for simple transforms and filters, and plain loops for anything complex.
- Prefer unpacking (
first, *rest = items) over indexing for readability. - Reach for
dequeorsetwhen front-of-list operations or fast membership checks dominate.