Lecture 5 of 1419 minInteractiveFree lecture

Collections: lists, tuples, dicts and sets

Four built-in collections do most of the work in real Python programs. Learn what each is for, why looking something up in a dict or set is so much faster than in a list, and how to write collections concisely with comprehensions.

In this lecture you will

  • Choose between list, tuple, dict and set for a given job
  • Explain why dict and set lookups stay fast as they grow
  • Explain why dict keys must be hashable
  • Build collections with list, dict and set comprehensions

Nearly every real program needs to hold groups of values: rows from a file, settings, users, results. Python provides four built-in collections, each designed for a different job. Choosing the right one makes code shorter, clearer and often dramatically faster.

The four workhorses

ExampleOrderedChangeableDuplicatesTypical use
list[3, 1, 3]yesyesyesa sequence of items you add to, sort and loop over
tuple("web-1", 8080)yesnoyesa fixed group of related values, such as a record or a pair
dict{"asha": 101}yes (insertion order)yeskeys uniquelooking values up by a key
set{"web", "db"}noyesnounique items and fast membership tests
servers = ["web-1", "web-2"]           # list
servers.append("web-3")

endpoint = ("api.example.com", 443)    # tuple
host, port = endpoint                  # unpacking

ext = {"asha": 101, "ravi": 102}       # dict
ext["meera"] = 103
print(ext.get("john", "unknown"))      # 'unknown' instead of a KeyError

tags = {"urgent", "billing"}           # set
print("urgent" in tags)                # True

Indexing and slicing

Lists, tuples and strings are sequences: every item has a position, counted from 0. Negative positions count from the end, so temps[-1] is the last item. A slice, written [start:stop:step], copies part of a sequence: it begins at start, stops before stop and moves step positions at a time. Leave out any part to get the default: the beginning, the end, or a step of 1.

InteractiveSlicing a listPick a slice or set your own
Loading visual…

Two facts save hours of debugging: stop is never included, and slices never raise IndexError: positions beyond the ends are simply clipped. A slice is a new list; changing it doesn’t change the original.

Why dict and set lookups are fast

Ask whether a value is in a list, and Python compares it with each item in turn. With a million items, that can mean a million comparisons. Ask the same of a dict or set, and the answer comes back almost instantly, however large it grows. The secret is a hash table.

Python computes a hash of the key — a large integer derived from its contents — and uses it to jump straight to a slot in an internal table. If that slot is taken by a different key (a collision), it tries another slot. Try inserting and looking up names below, and compare the work with a list scan.

InteractiveInside a dict: hashing, slots and probingInsert or look up a key
Loading visual…

Simplified: Python’s real hash function, table layout and probing order are more elaborate, and string hashes change between runs for security.

Because the table grows before it gets crowded, most lookups need only one or two probes. In the language of algorithms, list membership is O(n) — it grows with the number of items — while dict and set lookups are O(1) on average.

Keys must be hashable

A dict finds keys by their hash, so a key’s hash must never change while it is stored. That’s why keys (and set members) must be hashable: strings, numbers, booleans, None and tuples of these all work. Lists, dicts and sets are mutable and can’t be keys. If you need a composite key, use a tuple — routes[("DEL", "BLR")].

Comparing collections with set operations

Sets support the operations you may know from Venn diagrams, which turns “compare these two lists” into a single expression. Suppose you have the servers in your inventory and the servers that report to your monitoring system:

inventory = {"web-1", "web-2", "db-1", "cache-1", "batch-1"}
monitored = {"web-1", "web-2", "db-1", "db-2"}
InteractiveWhich servers are we not watching?Pick an operation
Loading visual…

Each operator has a method form, such as inventory.difference(monitored). The methods also accept lists and other iterables, so you can compare a set with a list without converting it first.

Comprehensions

A comprehension builds a new collection from an existing one in a single expression:

prices = [120, 85, 240, 60]

with_tax = [round(p * 1.18, 2) for p in prices]            # list
expensive = [p for p in prices if p > 100]                 # filtered list
lookup = {name: len(name) for name in ["asha", "ravi"]}    # dict
domains = {email.split("@")[1] for email in emails}        # set of unique domains

Read it as English: “p times 1.18, for each p in prices”. Comprehensions are usually clearer than an empty collection plus a loop — until they get long. If you need nested loops and several conditions, a regular loop is kinder to the next reader.

That completes the fundamentals module. You can now read and write Python with a precise picture of what it does. Module 2 applies these foundations to real programs — text, files, errors, packages and object-oriented design.

Key takeaways

  • Lists are ordered and changeable; tuples are ordered and fixed; dicts map keys to values; sets hold unique items.
  • Dicts and sets use hash tables, so checking for a key takes about the same time with ten items or ten million.
  • Keys and set members must be hashable — in practice, immutable values such as strings, numbers and tuples.
  • Comprehensions express “build a collection from another” in one readable line.

Check your understanding

3 questions · answers explained

Q1You need to check, many times per second, whether a user ID is in a list of 2 million blocked IDs. What should you use?

in on a list compares items one by one — up to 2 million comparisons. A set uses a hash table, so a membership check takes roughly constant time regardless of size.

Q2Why can’t a list be used as a dictionary key?

A dict places each key according to its hash. If a key could change, its hash would change and the dict could no longer find it. Immutable types such as tuples of numbers work fine as keys.

Q3What does {w.lower() for w in ["Apple", "apple", "Banana"]} produce?

Curly braces with a single expression make a set comprehension. The lowercased words are collected into a set, which drops the duplicate “apple”.

You’ve finished the free lectures.

Continue with the remaining 9 lectures of Python Programming — one-time purchase of $39₹2,499.