Coding tips

Python List vs Tuple vs Set vs Dictionary: Differences, Speed and When to Use Each (Tested Examples)

Use a list for an ordered collection you'll change, a tuple for a fixed record that shouldn't change, a set for unique items and fast membership tests, and a dictionary to look values up by key. Here are the differences with tested code, timings and memory sizes.

By 11 min read 2 views
Cover image for Python List vs Tuple vs Set vs Dictionary: Differences, Speed and When to Use Each (Tested Examples)

Use a list for an ordered collection you'll add to or change, a tuple for a fixed group of values that shouldn't change (like coordinates or a function returning two things), a set when you need unique items or fast "is this in here?" checks, and a dict when you want to look values up by a key. Lists and tuples keep order and allow duplicates; sets remove duplicates and have no index; dictionaries keep insertion order and map unique keys to values. In my tests on Python 3.13, checking membership in a 100,000-item set was over 20,000 times faster than in a list.

These four are the core built-in collections in Python, and almost every program you write will use at least two of them. Picking the right one makes code shorter, faster and much harder to break. Picking the wrong one leads to classic errors like TypeError: unhashable type: 'list' or a script that crawls through a big file.

Every example below ran on Python 3.13.5, and the output blocks are copied straight from my terminal, including the error messages and the speed and memory measurements.

In this guide:

  • List vs tuple vs set vs dict at a glance
  • The same data in all four
  • List: the everyday ordered, changeable collection
  • Tuple: a fixed record that can't change
  • Set: unique items and fast membership checks
  • Dictionary: look things up by key
  • Speed test: how fast is 'in' for each type?
  • Memory test: which one uses the least?
  • Hashable vs unhashable: the 'unhashable type' error
  • Converting between list, tuple, set and dict
  • Which one should you use?
  • Frequently asked questions

List vs tuple vs set vs dict at a glance

Featurelisttuplesetdict
Syntax[1, 2, 3](1, 2, 3){1, 2, 3}{"a": 1}
OrderedYesYesNoYes (insertion order)
Mutable (changeable)YesNoYesYes
DuplicatesAllowedAllowedRemovedKeys unique, values can repeat
Access byIndex x[0]Index x[0]No index (loop or in)Key x["a"]
Membership test inSlow (checks each item)Slow (checks each item)Fast (hash lookup)Fast on keys
Can be a dict key or set itemNoYes, if its items are hashableNo (use frozenset)No
Empty literal[]()set(){}

The official Python data structures tutorial covers all four in one place if you want the reference version.

The same data in all four

The fastest way to feel the difference is to put identical data into each one. Note that "green" appears twice:

lst = ["red", "green", "blue", "green"]
tup = ("red", "green", "blue", "green")
st  = {"red", "green", "blue", "green"}
dct = {"red": 1, "green": 2, "blue": 3, "green": 4}
print(lst); print(tup); print(st); print(dct)
print(len(lst), len(tup), len(st), len(dct))
['red', 'green', 'blue', 'green']
('red', 'green', 'blue', 'green')
{'red', 'blue', 'green'}
{'red': 1, 'green': 4, 'blue': 3}
4 4 3 3

Three things just happened:

  • The list and tuple kept all four items, in order, duplicates included.
  • The set silently dropped the second "green", and the order changed.
  • The dict kept one "green" key, but its value is 4: a repeated key overwrites the earlier value while keeping its original position.

In real projects you'll often combine them: a list of dicts is the natural shape for table rows, and it's exactly what you pass to csv.DictWriter in my guide to writing a list to CSV.

List: the everyday ordered, changeable collection

A list is your default choice when you have a sequence of things and you'll add, remove, sort or change them. Shopping baskets, rows read from a CSV, lines from a log file, results you're collecting in a loop.

lst = ["red", "green", "blue", "green"]
lst.append("pink")
print(lst)
print(lst[0])
['red', 'green', 'blue', 'green', 'pink']
red

Lists support indexing, slicing, sort(), insert(), pop() and much more. They're also what list comprehensions build; my list comprehension examples show the most useful patterns.

One thing to watch: assigning a list to a new name doesn't copy it. Both names point to the same list:

a = [1, 2]
b = a
b.append(3)
print(a)
[1, 2, 3]

Use b = a.copy() or b = list(a) when you want an independent copy.

Tuple: a fixed record that can't change

A tuple looks like a list with round brackets, but once it's created you can't add, remove or replace items. That's a feature, not a limitation: it tells anyone reading your code that this group of values belongs together and shouldn't be edited.

tup = ("red", "green", "blue")
tup.append("pink")
AttributeError: 'tuple' object has no attribute 'append'
tup[0] = "pink"
TypeError: 'tuple' object does not support item assignment

Tuples shine for coordinates, RGB colours, database rows, and returning several values from a function, which you can unpack straight into variables:

def min_max(nums):
    return min(nums), max(nums)

lo, hi = min_max([4, 9, 1])
print(lo, hi)
1 9

A common beginner trap is the single-item tuple. The comma makes the tuple, not the brackets:

print(type(("solo")), type(("solo",)))
<class 'str'> <class 'tuple'>

When tuple positions start getting confusing, collections.namedtuple lets you name each field (point.x instead of point[0]) while keeping it immutable.

Set: unique items and fast membership checks

A set stores each value only once and has no positions. That means you can't index it:

st = {"red", "green", "blue"}
st[0]
TypeError: 'set' object is not subscriptable

Sets also don't promise any order. For strings, the order can change between runs because Python randomises string hashing. I ran the same line with two different hash seeds:

$ PYTHONHASHSEED=1 python3 -c 'print({"red","green","blue"})'
{'red', 'green', 'blue'}
$ PYTHONHASHSEED=2 python3 -c 'print({"red","green","blue"})'
{'blue', 'red', 'green'}

What sets are brilliant at is maths-style comparisons between groups. Here are students taking Python and JavaScript classes:

python_students = {"Ayan", "Mim", "Rafi"}
js_students = {"Mim", "Tania", "Rafi"}
print(sorted(python_students & js_students))   # in both
print(sorted(python_students | js_students))   # in either
print(sorted(python_students - js_students))   # Python only
print(sorted(python_students ^ js_students))   # in exactly one
['Mim', 'Rafi']
['Ayan', 'Mim', 'Rafi', 'Tania']
['Ayan']
['Ayan', 'Tania']

Watch out for {}: it makes an empty dict, not an empty set. Use set(). And because 1 == True == 1.0 in Python, a set treats them as the same value: {1, True, 1.0} printed as {1} in my test. The built-in types documentation lists every set method, including issubset() and isdisjoint().

Dictionary: look things up by key

A dictionary maps keys to values. Use it whenever you'd otherwise search a list to find "the item for X": a user's settings, prices by product code, word counts, JSON data.

counts = {}
for w in "the cat and the hat and the bat".split():
    counts[w] = counts.get(w, 0) + 1
print(counts)
{'the': 3, 'cat': 1, 'and': 2, 'hat': 1, 'bat': 1}

Since Python 3.7, dictionaries officially remember insertion order, so new keys go on the end:

d = {"b": 2, "a": 1}
d["c"] = 3
print(list(d))
['b', 'a', 'c']

Use d.get(key, default) instead of d[key] when a key might be missing; the square-bracket version raises KeyError. If you need a dictionary that can't be changed, Python 3.15 is adding a built-in frozendict, which I covered separately.

Speed test: how fast is 'in' for each type?

This is where the choice really matters. Checking x in collection on a list or tuple means Python looks at items one by one. A set or dict uses a hash table and jumps almost straight to the answer. I timed 1,000 lookups of the last item in a 100,000-item collection with the timeit module, taking the best of five runs:

import timeit
n = 100_000
setup = f"data_list=list(range({n})); data_tuple=tuple(data_list); data_set=set(data_list); data_dict=dict.fromkeys(data_list); x={n-1}"
for name in ["data_list", "data_tuple", "data_set", "data_dict"]:
    t = min(timeit.repeat(f"x in {name}", setup=setup, number=1000, repeat=5))
    print(f"{name:11} 'x in' x1000: {t*1000:8.3f} ms")
data_list   'x in' x1000:  380.818 ms
data_tuple  'x in' x1000:  337.030 ms
data_set    'x in' x1000:    0.017 ms
data_dict   'x in' x1000:    0.019 ms

That's roughly 0.38 seconds for the list against 0.017 milliseconds for the set. Your numbers will differ by machine, but the gap won't: list membership gets slower as the list grows, while set and dict lookups stay roughly constant on average. The Python wiki's time complexity page lists this as O(n) for lists and O(1) on average for sets and dicts.

Creating them is a different story. Building a tuple literal was the quickest, and sets and dicts cost more to build because they have to hash every item:

list(range(1000))            x10000:   79.57 ms
tuple(range(1000))           x10000:   86.35 ms
set(range(1000))             x10000:  108.87 ms
dict.fromkeys(range(1000))   x10000:  179.60 ms
[1,2,3,4,5]                  x10000:    0.23 ms
(1,2,3,4,5)                  x10000:    0.08 ms

The practical rule: if you're going to check membership many times, convert to a set once and reuse it. If you only loop through the data, a list is fine.

Memory test: which one uses the least?

I measured the container itself with sys.getsizeof() (this counts the container, not the integers inside it) on 64-bit Linux:

import sys
data = list(range(1000))
print("list ", sys.getsizeof(data))
print("tuple", sys.getsizeof(tuple(data)))
print("set  ", sys.getsizeof(set(data)))
print("dict ", sys.getsizeof(dict.fromkeys(data)))
print(sys.getsizeof([1,2,3]), sys.getsizeof((1,2,3)), sys.getsizeof({1,2,3}), sys.getsizeof({1:1,2:2,3:3}))
list  8056
tuple 8040
set   32984
dict  36952
88 64 216 224
Type1,000 items (bytes)3 items (bytes)
tuple8,04064
list8,05688
set32,984216
dict36,952224

Tuples are the leanest, lists are close behind (they keep a little spare room for appending), and sets and dicts use about four times as much because of their hash tables. That extra memory is the price of the fast lookups above, and for most scripts it's well worth paying.

Hashable vs unhashable: the 'unhashable type' error

Set items and dictionary keys must be hashable, which roughly means "can't change". Lists, sets and dicts can change, so they can't be keys:

{["a"]: 1}
TypeError: unhashable type: 'list'

The fix is usually to use a tuple instead, which works perfectly as a key, for example for map coordinates:

print({(51.5, -0.12): "London"})
{(51.5, -0.12): 'London'}

There's a catch: a tuple is only hashable if everything inside it is hashable. A tuple holding a list fails too:

hash((1, [2, 3]))
TypeError: unhashable type: 'list'

For a set you want to use as a key, there's frozenset. Order doesn't matter, so both of these find the same entry:

perms = {frozenset({"read", "write"}): "editor"}
print(perms[frozenset({"write", "read"})])
editor

The Python glossary defines hashable precisely if you want the formal version.

Converting between list, tuple, set and dict

You can turn any of these into another with the constructor functions. The most useful conversion is removing duplicates. set() does it but scrambles the order; dict.fromkeys() keeps the original order:

emails = ["a@x.com", "b@x.com", "a@x.com", "c@x.com", "b@x.com"]
print(list(dict.fromkeys(emails)))
['a@x.com', 'b@x.com', 'c@x.com']

I compared five ways to do this in my guide to removing duplicates from a list. Other handy conversions:

  • tuple(my_list) to freeze a list before using it as a key.
  • list(my_set) or sorted(my_set) when you need indexing or a stable order.
  • dict(zip(keys, values)) to pair two lists into a dictionary.
  • list(my_dict) for the keys, list(my_dict.items()) for key/value tuples.

Equality across types is strict: [] == () is False in my test, while tuple([1, 2]) == (1, 2) is True.

Which one should you use?

If you need to…UseExample
Keep items in order and change themlistTo-do items, CSV rows
Store a fixed record or return several valuestuple(lat, lon), (min, max)
Remove duplicates or check "have I seen this?"setVisited URLs, unique tags
Compare two groupssetStudents in both classes
Look something up by name or IDdictSettings, prices, word counts
Use a collection as a dict keytuple or frozensetGrid positions, permission sets
Save memory on large fixed datatupleRead-only lookup tables

When in doubt, start with a list. Switch to a set the moment you write if x in big_list inside a loop, and switch to a dict the moment you find yourself searching a list for a matching ID. For quick conversions and text jobs while you work, try the free tools on mfaysal.com.

Frequently asked questions

What is the main difference between a list and a tuple in Python?

A list is mutable, so you can add, remove and change items after creating it. A tuple is immutable and can't be changed. Tuples use slightly less memory and can be used as dictionary keys if their contents are hashable.

Is a set faster than a list in Python?

For membership checks like x in data, yes, by a huge margin on large collections, because sets use hashing. In my test with 100,000 items, a set was over 20,000 times faster. For looping through every item, the difference is small.

Are Python dictionaries ordered?

Yes. Since Python 3.7, dictionaries keep keys in the order you inserted them, and this is part of the language guarantee. Sets are not ordered, and their printed order can change between runs.

Why do I get TypeError: unhashable type: 'list'?

You tried to use a list as a dictionary key or put it in a set. Lists can change, so Python can't hash them. Convert it to a tuple with tuple(my_list), or use frozenset if order doesn't matter.

How do I create an empty set in Python?

Use set(). Writing {} creates an empty dictionary, not a set. Once a set has items, curly braces work, for example {1, 2, 3}.

When should I use a tuple instead of a list?

Use a tuple when the group of values is fixed and belongs together, such as coordinates, RGB colours or a function returning two results. It signals to readers that the data shouldn't change and stops accidental edits.

Can a dictionary have duplicate keys?

No. Keys must be unique. If you write the same key twice, the later value replaces the earlier one, but the key keeps its original position. Values can repeat as often as you like.

Which uses the least memory: list, tuple, set or dict?

Tuples use the least, lists are almost the same, and sets and dicts use around four times as much for the same number of items because of their hash tables. In my test, 1,000 integers took 8,040 bytes as a tuple and 32,984 bytes as a set.

Last checked: 31 October 2026. Figures, settings and guidance can change, so confirm anything important with the sources linked above.

Share X LinkedIn WhatsApp Facebook
Was this helpful?

0%