Lists, dicts and comprehensions

Slicing, mutability gotchas, comprehension syntax, and choosing the right collection for the job.

Lists

nums = [3, 1, 2]
nums.append(4)          # [3, 1, 2, 4]
nums.extend([5, 6])
nums.insert(0, 0)
last = nums.pop()       # removes and returns the last item
nums.sort()             # in place; sorted(nums) returns a copy

first, *rest = nums     # unpacking
OperationCost
Index / append / pop from endO(1)
Insert or delete at the frontO(n) — use deque
x in listO(n) — use a set for repeated checks

The aliasing trap

Assignment copies the reference, so two names can point at one list. The classic bug is a default mutable argument, which is evaluated once at definition time and shared by every call.

a = [1, 2]
b = a
b.append(3)
print(a)  # [1, 2, 3]  - same object

b = a[:]           # shallow copy
b = list(a)

# wrong: the default list is shared between calls
def add(item, bucket=[]):
    bucket.append(item)
    return bucket

# right
def add(item, bucket=None):
    bucket = bucket if bucket is not None else []
    bucket.append(item)
    return bucket
⚠️
[[0]] * 3 creates three references to the same inner list — changing one changes all. Use a comprehension: [[0] for _ in range(3)].

Comprehensions

squares = [n * n for n in range(10)]
evens   = [n for n in nums if n % 2 == 0]

# dict comprehension
by_id = {u['id']: u for u in users}

# conditional transformation
labels = ['even' if n % 2 == 0 else 'odd' for n in nums]

# set comprehension - deduplicates
unique_tags = {t.lower() for t in tags}

Read them right to left: the expression first, then the loop, then the filter. If a comprehension needs more than one condition or a nested loop, a plain for block is clearer.

Dicts

user = {'id': 1, 'name': 'Ada'}
user.get('email')            # None instead of KeyError
user.get('email', 'n/a')     # with default
user.setdefault('role', 'guest')

for key, value in user.items():
    print(key, value)

merged = {**user, 'role': 'admin'}   # Python 3.5+
counts = dict(Counter(words))        # tallying done for you
💡
Dicts preserve insertion order (guaranteed since 3.7), so you rarely need OrderedDict anymore. Use collections.defaultdict when building groups.

FAQ

tuple or list?
Lists for homogeneous sequences that change size; tuples for fixed-shape records (coordinates, return values). Tuples are also hashable, so they work as dict keys.
Why is my loop skipping items while removing?
Mutating a list while iterating it shifts subsequent indices. Iterate over a copy (for x in list[:]) or build a new list with a comprehension.

Python: getting started Functions and modules

Last refreshed 2026-09-17.