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.