Say you run a small store in Columbus, Ohio. Today’s register log has four scans, and your catalog prices three SKUs at $24.99, $89.50 and $12.75. That’s the difference between list and dictionary in Python in one picture.
The scans belong in a list, an ordered sequence you read by position. The catalog belongs in a dictionary, which finds a price by its key in one step.
In this article, I’ll walk you through how each one stores and reads data, what each one does with a missing item, and I’ll time a real lookup in both. I ran every snippet on Python 3.12.5.
The sample store data we’ll use for the list and the dictionary
Here’s the data every section below works with:
orders = ["SKU-1001", "SKU-2040", "SKU-1001", "SKU-3300"] # today's scans, in order
prices = {"SKU-1001": 24.99, "SKU-2040": 89.50, "SKU-3300": 12.75} # catalog: SKU -> price
ordersis a list of four scans, and SKU-1001 appears twicepricesis a dictionary with three SKUs, each mapped to a USD price- The real order total is $152.23
That repeated SKU-1001 matters: a list keeps duplicates, but a dictionary key can only exist once. The square vs curly brackets are explained in square and curly brackets in Python.
1. How a list and a dictionary store and read data
A list stores values in order and numbers them from 0. A dictionary stores key-value pairs, so you ask for a label instead of a position.
Same four scans and three prices here. Let me show you:
orders = ["SKU-1001", "SKU-2040", "SKU-1001", "SKU-3300"] # today's scans, in order
prices = {"SKU-1001": 24.99, "SKU-2040": 89.50, "SKU-3300": 12.75} # catalog: SKU -> price
print(orders[0], orders[-1]) # first and last scan, by position
print(prices["SKU-2040"]) # price, by key
print(len(orders), "scans,", len(prices), "SKUs")
prices["SKU-1001"] = 22.99 # same key again: the value is replaced
print(prices)
Output:
SKU-1001 SKU-3300
89.5
4 scans, 3 SKUs
{'SKU-1001': 22.99, 'SKU-2040': 89.5, 'SKU-3300': 12.75}

How does this code work?
orders[0] and orders[-1] read the first and last scans. Negative indexes count from the end.
prices["SKU-2040"] skips positions entirely and returns 89.5. The len() calls show four items vs three keys, as covered in the len() function in Python.
So here’s the catch: assigning prices["SKU-1001"] again didn’t add a second entry. It replaced $24.99 with $22.99, because keys are unique.
Pro Tip: Since Python 3.7, dictionaries keep insertion order. Older answers that call dicts “unordered” are out of date, but you still can’t read a dict by position.
2. What happens when a list index or dictionary key is missing?
Both raise an error, but the dictionary gives you a safe way out.
orders = ["SKU-1001", "SKU-2040", "SKU-1001", "SKU-3300"] # today's scans, in order
prices = {"SKU-1001": 24.99, "SKU-2040": 89.50, "SKU-3300": 12.75} # catalog: SKU -> price
try:
print(orders[10])
except IndexError as err:
print("IndexError:", err)
try:
print(prices["SKU-9999"])
except KeyError as err:
print("KeyError:", err)
print(prices.get("SKU-9999", 0.00)) # safe lookup with a default
print(24.99 in prices, 24.99 in prices.values())
Output:
IndexError: list index out of range
KeyError: 'SKU-9999'
0.0
False True

How does this code work?
The list has four scans, so index 10 raises IndexError. The catalog has no SKU-9999, so the bracket lookup raises KeyError.
prices.get("SKU-9999", 0.00) returns the default instead of crashing. The last line shows that in checks a dictionary’s keys, not its values; see checking if a Python dictionary contains a key.
3. Why is a dictionary lookup faster than a list?
This is the difference that matters most on real data. I timed one in check against a 100,000-SKU catalog stored both ways.
import timeit
skus = [f"SKU-{n}" for n in range(100_000)] # a catalog of 100,000 SKUs
as_list = skus
as_dict = dict.fromkeys(skus, 19.99)
target = "SKU-99999" # the last one: worst case for the list
t_list = min(timeit.repeat(lambda: target in as_list, number=100, repeat=5)) / 100
t_dict = min(timeit.repeat(lambda: target in as_dict, number=100, repeat=5)) / 100
print(f"list: {t_list * 1e6:10,.2f} microseconds per check")
print(f"dict: {t_dict * 1e6:10,.2f} microseconds per check")
print(f"dict was about {t_list / t_dict:,.0f}x faster")
Output:
list: 677.79 microseconds per check
dict: 0.04 microseconds per check
dict was about 18,828x faster

How does this code work?
target in as_list compares the target with every item from the start. SKU-99999 is last, so it checks all 100,000.
target in as_dict hashes the key and jumps straight to its slot, so the time barely grows with size. The in keyword itself is covered in the in operator in Python.
4. Using a list and a dictionary together
Real code often uses both: the list records what happened, and the dictionary answers questions about it.
orders = ["SKU-1001", "SKU-2040", "SKU-1001", "SKU-3300"] # today's scans, in order
prices = {"SKU-1001": 24.99, "SKU-2040": 89.50, "SKU-3300": 12.75} # catalog: SKU -> price
total = sum(prices[sku] for sku in orders)
print(f"Order total: ${total:,.2f}")
counts = {}
for sku in orders:
counts[sku] = counts.get(sku, 0) + 1
print(counts)
for sku, qty in counts.items():
print(f"{sku}: {qty} x ${prices[sku]:.2f} = ${qty * prices[sku]:.2f}")
Output:
Order total: $152.23
{'SKU-1001': 2, 'SKU-2040': 1, 'SKU-3300': 1}
SKU-1001: 2 x $24.99 = $49.98
SKU-2040: 1 x $89.50 = $89.50
SKU-3300: 1 x $12.75 = $12.75

How does this code work?
The generator walks the four scans in order and looks up each price by key, giving $152.23.
The counts dictionary uses get(sku, 0) + 1 to tally scans, then items() prints each line. More on that loop in iterating through a dictionary in Python.
Pro Tip: If you only need to know whether something is present, with no value attached, a set gives the same fast lookup as a dictionary.
Picking the right one: list vs dictionary
| Question | List | Dictionary |
|---|---|---|
| Access by | Position (0, 1, -1) | Key (“SKU-2040”) |
| Duplicates | Allowed | Keys must be unique |
| Order | Always kept | Insertion order (3.7+) |
x in ... | Scans every item | Hash lookup, near constant time |
| Best for | Sequences, logs, sorting | Lookups by ID, name or code |
If tuples and sets are also on your shortlist, the four-way overview is in comparing lists, tuples, sets and dictionaries.
Things to Keep in Mind with Lists and Dictionaries
- Repeated
x in big_listchecks are slow. Build a dictionary or set once, then check that. inon a dictionary checks keys only. Use.values()to search prices.- Assigning an existing key silently overwrites it. Check with
infirst if that matters. - Dictionary keys must be hashable, so a list can’t be a key. Use a tuple instead.
These guides go well with this one:
- Convert a dictionary to a list in Python
- Work with a dictionary of lists in Python
- Python dictionary comprehension
- Arrays vs lists in Python
Frequently asked questions
What is the main difference between a list and a dictionary in Python?
A list is an ordered sequence read by position; a dictionary maps unique keys to values and is read by key.
Is a dictionary faster than a list?
For lookups by key and membership checks, yes, by a wide margin on large data. Reading a list by index is fast too.
Can a list have duplicate values?
Yes. Dictionary values can repeat as well, but each key can appear only once.
Are Python dictionaries ordered?
Yes, since Python 3.7 they keep insertion order. They still can’t be read by position.
When should I use a list instead of a dictionary?
Use a list when order matters, items have no natural key, or you’ll mostly loop, sort or slice.
Where are lists and dictionaries documented?
See Data Structures in the Python tutorial.

Bijay Kumar is a 13-time Microsoft MVP with more than 18 years in software development, and the founder of Python Guides and TSinfo Technologies. He started out building .NET and SharePoint solutions at HP, TCS and KPIT before moving into Python, machine learning and AI, and he also builds web apps with TypeScript and React. He writes the tutorials here himself, and every example is run before publishing so you see the real output. More about Bijay · Microsoft MVP profile · LinkedIn