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 b affect a (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

  1. result = my_list.sort() sets result to None — use sorted() if you need the return value
  2. backup = data creates an alias, not a backup — use .copy()
  3. [[0] * n] * m creates m references to the same inner list — use a comprehension
  4. Removing items while looping over range(len(lst)) skips elements and then crashes with IndexError — iterate backwards, use a while loop, or build a new list
  5. 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]) (the key function picks what to compare)
  • Bulk delete by priority uses a comprehension to filter, then .clear() + .extend() to update the caller's list in place (rebinding tasks = remaining inside the function wouldn't affect main()'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.