Collections

This section documents the current Python release line as published at the official Python documentation, which is the reference these pages are written and verified against. No specific patch version is pinned.

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

This section’s bibliography lists the reference material consulted while preparing these pages.

Python has four built-in collection types — list, tuple, set, and dict — covered together in the tutorial’s Data Structures chapter. Lists and tuples are sequences, sets are unordered collections of unique elements, and dicts are mappings from keys to values.

Lists

A list is a mutable, ordered sequence, documented under Sequence Types — list, tuple, range. Index with [] (negative indices count from the end) and slice with [start:stop:step]:

fruits = ["apple", "banana", "cherry", "date"]

fruits[0]        # 'apple'
fruits[-1]       # 'date'          (last element)
fruits[1:3]      # ['banana', 'cherry']
fruits[::-1]     # ['date', 'cherry', 'banana', 'apple']   (reversed)

Mutating methods change the list in place: .append() adds one element at the end, .insert() adds at a given position, and .sort() reorders the list itself and returns None. The built-in sorted(), by contrast, returns a new list and leaves the original untouched:

numbers = [3, 1, 4, 1, 5, 9]
numbers.append(2)          # [3, 1, 4, 1, 5, 9, 2]
numbers.insert(0, 0)       # [0, 3, 1, 4, 1, 5, 9, 2]

numbers.sort()             # mutates in place: [0, 1, 1, 2, 3, 4, 5, 9]

original = [3, 1, 2]
ordered = sorted(original)   # new list: [1, 2, 3]
print(original)              # unchanged: [3, 1, 2]

A list comprehension builds a new list from an iterable in a single expression — see Iterators, Generators, and Comprehensions for the full comprehension syntax including if clauses and nesting:

squares = [n ** 2 for n in range(6)]         # [0, 1, 4, 9, 16, 25]
evens = [n for n in range(10) if n % 2 == 0]  # [0, 2, 4, 6, 8]

Tuples

A tuple is an immutable sequence — once created, its elements cannot be reassigned, added, or removed. Use del to remove the whole name binding, not an element:

point = (3, 4)
# point[0] = 5     # TypeError: 'tuple' object does not support item assignment

del point          # removes the name 'point' entirely, not one element

Packing collects multiple values into a tuple; unpacking spreads a tuple’s elements back into separate names, including a starred catch-all for "the rest":

coordinates = 3, 4, 5              # packing (parentheses are optional)
x, y, z = coordinates              # unpacking: x=3, y=4, z=5

first, *middle, last = (1, 2, 3, 4, 5)
print(first, middle, last)         # 1 [2, 3, 4] 5

Prefer a tuple over a list when the collection is fixed-size and heterogeneous (a coordinate pair, a database row) or when its immutability matters — for example, because it must be hashable to use as a dict key or set member. Prefer a list when the collection is homogeneous and its length or contents will change.

Sets

A set is an unordered collection of unique, hashable elements, documented under Set Types — set, frozenset. Adding a duplicate is a no-op:

tags = {"python", "web", "python", "guide"}
print(tags)             # {'python', 'web', 'guide'}  (duplicate dropped, order not guaranteed)

Set operations mirror mathematical set theory — union (|), intersection (&), and difference (-):

a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

a | b     # {1, 2, 3, 4, 5, 6}   union
a & b     # {3, 4}               intersection
a - b     # {1, 2}               difference: in a but not b
a ^ b     # {1, 2, 5, 6}         symmetric difference

A set comprehension uses \{…​} instead of […​]:

lengths = {len(word) for word in ["a", "bb", "ccc", "dd"]}   # {1, 2, 3}

Note that \{} alone creates an empty dict, not an empty set — use set() for that.

Dictionaries

A dict maps hashable keys to values, documented under Mapping Types — dict. .get() avoids a KeyError by returning a default (None unless given) when the key is absent:

person = {"name": "Ada", "age": 36}

person["name"]              # 'Ada'
person.get("email")         # None            (key missing, no error)
person.get("email", "n/a")  # 'n/a'           (explicit default)

Iterate over .keys(), .values(), or .items() — the last gives key-value pairs, typically unpacked in a for loop:

for key in person.keys():
    print(key)                     # 'name', 'age'

for value in person.values():
    print(value)                   # 'Ada', 36

for key, value in person.items():
    print(f"{key} = {value}")      # 'name = Ada', 'age = 36'

A dict comprehension has the shape \{key: value for …​ in …​}:

squares_by_n = {n: n ** 2 for n in range(5)}   # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

Since Python 3.7, dicts guarantee insertion order — iterating yields keys in the order they were first added, which earlier versions did not promise. Merge two dicts with | (keys from the right-hand operand win on conflict), or update one in place with |=:

defaults = {"color": "blue", "size": "M"}
overrides = {"size": "L", "stock": 10}

merged = defaults | overrides    # {'color': 'blue', 'size': 'L', 'stock': 10}

defaults |= overrides            # defaults updated in place, same result

Choosing Between Them

  • Need order and duplicates, and elements will be added, removed, or reordered? Use a list.

  • Need order and a fixed collection that should not change, or must be hashable (e.g. as a dict key)? Use a tuple.

  • Need to test membership fast and only care about uniqueness, not order? Use a set.

  • Need to look values up by a key rather than by position? Use a dict.

list and tuple are both sequence types — they support indexing, slicing, and iteration in a fixed order. set (and its immutable sibling frozenset) are set types — unordered, with no indexing. dict is the standard-library’s built-in mapping type. Membership testing (in) is \(O(1)\) on average for set and dict, but \(O(n)\) for list and tuple, since the latter must scan element by element:

big_list = list(range(100_000))
big_set = set(big_list)

99_999 in big_list   # True, but scans up to the whole list
99_999 in big_set    # True, and is a fast hash lookup

See Also