Key Takeaways: Lists and Tuples
One-Sentence Summary
Lists and tuples are Python's core sequence types — lists are mutable (changeable) and tuples are immutable (fixed) — and understanding that assignment creates aliases, not copies, is the threshold concept that prevents an entire category of bugs.
Lists vs. Tuples at a Glance
| Feature | List | Tuple |
|---|---|---|
| Syntax | [1, 2, 3] |
(1, 2, 3) |
| Mutable? | Yes — can add, remove, change | No — fixed after creation |
| Typical use | Collections that change | Fixed records, return values |
| Can be dict key? | No | Yes, if everything inside it is hashable (no lists) |
Has .append(), .sort(), etc.? |
Yes | No |
| One element | [42] |
(42,) (the comma makes the tuple) |
Essential List Methods
| Method | What It Does | Returns |
|---|---|---|
append(x) |
Add x to end |
None |
extend(iter) |
Add all items from iterable | None |
insert(i, x) |
Insert x at position i |
None |
remove(x) |
Remove first occurrence of x |
None |
pop(i) |
Remove at index i, return it |
Removed item |
sort() |
Sort in place | None |
sorted(list) (built-in function, not a method) |
Return new sorted list | New list |
index(x) |
Find first index of x |
Index |
count(x) |
Count occurrences | Count |
copy() |
Shallow copy | New list |
The Aliasing Rule
b = a # alias — same object, two names
b = a.copy() # copy — independent objects
- Alias: changes through
baffecta(and vice versa) - Copy: changes to the copy don't affect the original
- Shallow copy: copies the outer list, but inner objects are still shared
- Deep copy:
copy.deepcopy()— fully independent at every level
List Comprehension Pattern
[expression for variable in iterable if condition]
Use for simple transforms and filters. An if after the for filters items out; an x if cond else y before the for picks one of two values for every item. If it doesn't fit on one line, use a regular for loop.
Tuple Unpacking
lowest, highest = min_max(data) # catch multiple return values
a, b = b, a # swap without a temp variable
first, *rest = items # *rest collects the leftovers into a list
The number of names must match the number of items, unless one name is starred.
Three Iteration Patterns
for item in my_list: # when you just need the elements
for i, item in enumerate(lst): # when you need index + element
for a, b in zip(list1, list2): # when you have parallel lists
Common Gotchas
result = my_list.sort()setsresulttoNone— usesorted()if you need the return valuebackup = datacreates an alias, not a backup — use.copy()[[0] * n] * mcreatesmreferences to the same inner list — use a comprehension- Removing items while looping over
range(len(lst))skips elements and then crashes withIndexError— iterate backwards, use awhileloop, or build a new list append([4, 5])vs.extend([4, 5])— append adds one element (the list itself); extend adds each element
TaskFlow v0.7 Progress
- Tasks now stored as list of tuples:
(name, priority, created_at) - Can sort by priority using
sorted(tasks, key=lambda t: t[1])(thekeyfunction picks what to compare) - Bulk delete by priority uses a comprehension to filter, then
.clear()+.extend()to update the caller's list in place (rebindingtasks = remaininginside the function wouldn't affectmain()'s list) - The task list lives in
main()and is passed to each function, as in v0.5 and v0.6 - Tuple unpacking in loops:
for i, (name, priority, created) in enumerate(tasks, start=1):
What's Next
Chapter 9: Dictionaries and Sets — organize data by keys instead of position, enabling O(1) lookups. TaskFlow upgrades from tuples to dictionaries for named fields.