Recommended Free Tools
iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
Use a list when order, positional access, or changing contents matters. Use a tuple for an ordered group of values that should stay fixed. Use a set when distinct values, membership tests, or set operations matter and position does not. Use a frozenset when you need set behavior but also need an immutable value that can be hashed, for example as a dictionary key or as an element inside another set.
The distinctions below come from the Built-in Types reference in the Python Software Foundation’s documentation. The reference describes lists and tuples as sequence types and sets as unordered collections of distinct hashable objects. The examples and rules match the Python 3.14 release of that page; the live page may show a newer version, and the core behavior described here has been stable across Python 3 releases. Source: Built-in Types, Python documentation.
Choosing at a glance
The four types differ on a small set of properties. Most wrong choices come from ignoring one of them, usually order or hashability. The table lists the behavior the reference documents for each type.
Free tools Windows power users keep installed
One-click scans. No signup required.
| Property | list | tuple | set | frozenset |
|---|---|---|---|---|
| Keeps order and supports positional access (indexing, slicing) | Yes | Yes | No; unordered, no indexing or slicing | No; unordered, no indexing or slicing |
| Can be changed after creation | Yes | No | Yes | No |
| Can be hashed (used as a dict key or set member) | No | Only if every element is hashable | No | Yes, if its elements are hashable |
| Stores repeated values | Yes | Yes | No; holds distinct values only | No; holds distinct values only |
| Main purpose | Ordered, changeable sequence | Fixed ordered record or group | Unique members, membership tests, set algebra | Immutable, hashable set value |
Work through these questions in order. The first “yes” usually decides the type.
#1 Best Overall
- Does position matter, or do you need to read items by index or slice? If yes, use a list or tuple.
- Will the contents change after creation? If yes, use a list or set. If no, a tuple or frozenset fits.
- Do duplicates have no meaning, and do you mainly ask “is this value in the group?” or combine groups? If yes, use a set or frozenset.
- Must the value itself be hashable, for example as a dictionary key? If yes, use a tuple (with hashable contents) or a frozenset.
What each type is for
list: ordered and changeable
A list is the default sequence. It keeps insertion order, supports indexing and slicing, and lets you append, insert, remove, or replace items. Use it for ordered collections whose length or contents change, such as a queue of tasks being processed. The reference classes lists as mutable sequences, which is why they cannot serve as dictionary keys or set members.
tuple: ordered and fixed
A tuple is an ordered sequence that supports the same read-only operations as a list, including indexing, while its elements and their order cannot be changed through the tuple. That fixed shape makes tuples a good fit for a single record, such as a coordinate pair, or a group of values that should be passed around without being edited.
Rank #2
# A tuple is an ordered group whose structure should remain fixed.npoint = (4, 7)nx = point[0] # indexing worksn# point[0] = 9 # raises TypeError: 'tuple' object does not support item assignment
set: distinct members, no position
A set is an unordered collection of distinct hashable values. It does not record position or insertion order, and it has no indexing or slicing. What it provides is fast membership testing, duplicate removal, and set algebra such as union, intersection, and difference. Use it when the question is “is this value present?” rather than “what is at position 2?”
# A set removes duplicates and supports membership checks.nunique_tags = set(["python", "data", "python"])nif "python" in unique_tags:n print("found")nn# Set operations compare groups.nrequired = {"read", "write"}nimplemented = {"read", "write", "test"}nmissing = required - implemented # set()
frozenset: a set that can be a key
A frozenset has the same membership and set-algebra behavior as a set, but it cannot be changed after creation. Because it is immutable and hashable, it can be a dictionary key or an element of another set, roles a regular set cannot fill. Use it for a fixed group of permissions, tags, or configuration flags that must act as a single lookup key.
permissions = frozenset({"read", "write"})naccess_rules = {permissions: "editor"}nprint(access_rules[frozenset({"write", "read"})]) # editor
Hashability decides dictionary keys and set members
Set elements and dictionary keys must be hashable. That requirement is the most common reason a tuple or set fails where you expected it to work.
A tuple is hashable only when every element inside it is hashable. A tuple containing a list therefore looks immutable but cannot be hashed:
>>> hash((1, 2))n3713081631934410656n>>> hash((1, [2]))nTraceback (most recent call last):n File "<stdin>", line 1, in <module>nTypeError: unhashable type: 'list'
A set cannot be a member of another set or a dictionary key, because a set is mutable. If you need a set-like value in those roles, convert it to a frozenset first. If you need an ordered key, use a tuple whose contents are hashable, such as strings and numbers.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Pitfalls to avoid
- Empty sets. Write
set(). The literal{}creates an empty dictionary. Non-empty sets can use braces, as in{"a", "b"}. - One-element tuples. The comma creates the tuple, not the parentheses.
item,and(item,)are tuples;(item)is just the value. - Relying on set order. Do not depend on the order in which a set’s elements are iterated, and do not use a set where you need indexing or slicing.
- Expecting
pop()to return the first item.set.pop()removes and returns an arbitrary element. - Assuming every tuple is hashable. Check the contents before using a tuple as a key; see the example above.
- Treating subset checks as sorting. Subset comparisons such as
<=define a partial order. Two disjoint sets may compare neither as less than nor as greater than each other, so set comparisons cannot be used to sort. - Mixing operators and methods. Operators such as
&,|, and-require sets on both sides. Methods such as.intersection()and.union()accept any iterable, such as a list, which avoids confusing type errors.
A worked decision
Suppose you are writing a function that checks which required steps a build has not completed, then caches the results by configuration.
Best Value
- The step names are unique, and you only need the difference between two groups. A set fits, and
required - completedreads clearly. - The configuration must be a dictionary key. The set of enabled features is converted to a frozenset, so the key is hashable.
- The build sequence itself is ordered and its steps run in a fixed order. A tuple or list fits, and a list is the better choice if steps are added while the build is planned.
Each choice follows from one property in the table, which is why reviewing those properties first is quicker than trial and error.
Quick Recap
n
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

