Last 30 Days
No notifications
Lists are Python's most versatile data structure — ordered, mutable collections that can hold mixed types.
nums = [1, 2, 3, 4, 5]
mixed = [1, "hello", 3.14, True]
empty = []| Operation | Syntax | Result (for [10,20,30,40,50]) | |||
| First element | lst[0] | 10 | |||
| Last element | lst[-1] | 50 | |||
| Slice | lst[1:3] | [20, 30] | |||
| Step slice | lst[::2] | [10, 30, 50] | |||
| Reverse | lst[::-1] | [50, 40, 30, 20, 10] | Common List Methods | Method | Description |
append(x) | Add item to end | ||||
insert(i, x) | Insert at index i | ||||
remove(x) | Remove first occurrence of x | ||||
pop(i) | Remove & return item at index (default last) | ||||
sort() | Sort in place | ||||
reverse() | Reverse in place | ||||
extend(lst) | Add all items from another list |
A concise way to create lists:
squares = [x**2 for x in range(10)]
evens = [x for x in range(20) if x % 2 == 0]Tuples are ordered, immutable sequences. Use them for fixed collections:
point = (3, 7)
x, y = point # Tuple unpacking
rgb = (255, 128, 0)| Feature | List | Tuple |
| Mutable | ✅ Yes | ❌ No |
| Syntax | [1, 2] | (1, 2) |
| Use case | Dynamic data | Fixed records |
| Hashable | ❌ No | ✅ Yes (if elements are) |
> Tip: Use sorted() to get a new sorted list without modifying the original. len() works on both lists and tuples.
Lists and tuples are Python's two main *ordered sequences*. A list is a flexible, growable container; a tuple is its immutable, lighter sibling. Together they handle 80% of "hold a bunch of things in order" jobs.
fruits = ["apple", "banana", "cherry"]A list is an ordered, mutable, indexable collection. You can add, remove, replace, sort, and slice items. Internally it's a dynamic array of pointers — contiguous memory that grows as needed.
point = (3, 4)A tuple is the same shape but immutable — you can't change items after creation. Useful for fixed records (coords, RGB triples), dict keys, and function returns.
items = [10, 20, 30, 40, 50]
items[0] # 10 — first
items[-1] # 50 — last
items[1:4] # [20, 30, 40] — half-open
items[:3] # [10, 20, 30]
items[::2] # [10, 30, 50] — every other
items[::-1] # reversed copySlicing always returns a new list (copy). Negative indices count from the end. a[start:stop:step] — stop is exclusive.
lst.append(x) # add to end
lst.extend(other) # add many (like += other)
lst.insert(i, x) # insert at index
lst.pop() # remove & return last (default)
lst.pop(0) # remove & return first (slow, O(n))
lst.remove(x) # remove first occurrence of value
lst.sort() # in-place sort
lst.reverse() # in-place reverse
lst.count(x) # how many
lst.index(x) # first position of x
sorted(lst) # NEW sorted list (doesn't mutate)
len(lst), x in lst # size, membership1. b = a then mutating. Both names point to the same list. Use b = a.copy() (or a[:] / list(a)) for an independent copy.
2. def f(items=[]):. Default is shared across calls. Use items=None and assign inside.
3. Inserting at position 0 in a hot loop. insert(0, x) is O(n). Use collections.deque for fast both-end ops.
4. if x in big_list repeatedly. O(n) each time. If you do this often, use a set.
5. a == b vs a is b for lists. == compares values; is compares identity. You almost always want ==.
6. (x) is not a tuple. It's just x in parens. Use (x,) for a 1-tuple.
x, y = (3, 4) # tuple unpacking
first, *rest = [1, 2, 3, 4] # first=1, rest=[2,3,4]
head, *mid, tail = range(5) # head=0, mid=[1,2,3], tail=4
a, b = b, a # swap, no temp variableWorks with any iterable. Star-unpacking on the LHS is a Python superpower.
squares = [x*x for x in range(10)]
evens = [x for x in nums if x % 2 == 0]
flattened = [item for row in matrix for item in row]
mapped = [f(x) if x else 0 for x in items]Faster than for + append (loop runs in C). Don't nest more than two levels — readability collapses fast.
people.sort(key=lambda p: p["age"]) # by age
people.sort(key=lambda p: (p["city"], -p["age"])) # multi-key, age desc
import operator
people.sort(key=operator.itemgetter("age")) # often faster than lambdaSorting is stable — equal keys keep their relative order. Use sorted(...) for a fresh list, .sort() to mutate.
user = ("alice", 30, "admin")
name, age, role = userFor more readability, reach for collections.namedtuple or a @dataclass. Tuples are also the only collection (with frozenset) you can use as a dict key.
| Op | Cost |
a[i], len | O(1) |
append, pop() | O(1) amortised |
insert(0, x), pop(0), remove | O(n) |
x in a | O(n) |
a + b, slicing | O(k) (copies) |
sort | O(n log n) |
Left-end operations are slow because every element shifts. Use collections.deque for fast appendleft / popleft.
import copy
shallow = original.copy() # or list(original) / original[:]
deep = copy.deepcopy(original) # recursively copies nested objectsShallow copy duplicates the outer list but shares inner objects. Mutating a nested list in shallow will mutate it in original too. Reach for deepcopy only when you really need it (it's expensive).
set (O(1)).dict.collections.deque.numpy.ndarray (vectorised + tiny memory).tuple or frozenset.lst[:] = [] # clear in place (keeps same object)
lst[:] = other # replace contents in place
lst[2:2] = [99, 100] # insert without copying
lst[::-1] # reversed copyAssignment to a slice mutates the original list — useful when other code holds a reference to it.
1. Build a list of squares 0–9 using a comprehension; verify with == against a manual list.
2. Sort a list of dicts by two keys (e.g., city ascending, age descending) using sorted + key.
3. Demonstrate the shared-default-argument bug with def f(x, items=[]):, then fix it with items=None.
4. Replace a slow x in big_list check inside a loop by converting big_list to a set first; time both with time.perf_counter().