We’ve learned that sets are mutable collections, meaning we can add and remove items after they’re created. This behavior is similar to lists. But just as lists have an immutable counterpart in tuples (which we learned about in Post #58), sets also have an immutable version for situations where you need a guarantee that the collection will not change.
In this post, we’ll be introduced to the frozenset
. We’ll learn what it is, how it differs from a regular set
, and explore the key situations where this special data type is required.
What is a frozenset
?
A frozenset
is an immutable version of a set. It has the same core properties of being an unordered collection of unique elements, but with one major difference: once a frozenset
is created, its contents cannot be altered in any way.
You create a frozenset
using its constructor, passing in any iterable (like a list, tuple, or another set).
# Create a frozenset from a list with duplicates
frozen = frozenset([1, 2, 2, 3])
print(frozen)
print(type(frozen))
The output will be:
frozenset({1, 2, 3})
<class 'frozenset'>
Because it is immutable, a frozenset
does not have methods like .add()
, .remove()
, or .pop()
. Attempting to call them will result in an AttributeError
. However, all the non-modifying operations we learned about, like union (|
) and intersection (&
), work perfectly with frozensets.
The Main Use Case: Hashability
So why would we want an unchangeable set? The primary reason is that frozenset
objects are hashable, while regular set
objects are not. As we learned in our discussion on dictionary performance (Post #73), an object must be hashable (and therefore immutable) to be used as a dictionary key.
This opens up two important possibilities.
Using a frozenset
as a Dictionary Key
You cannot use a mutable set
as a dictionary key, as it can change. But you can use a frozenset
. This is useful if you want to map a collection of unique items to a value.
# A regular set cannot be a dictionary key
my_set = {1, 2}
# my_dict = {my_set: "value"} # This would cause a TypeError!
# A frozenset CAN be a dictionary key
my_frozenset = frozenset([1, 2])
my_dict = {my_frozenset: "value"}
print(my_dict)
The output is a valid dictionary: {frozenset({1, 2}): 'value'}
.
Using a frozenset
Inside a Set
For the same reason, the items contained within a set must also be immutable. This means you cannot have a set of sets. However, you can have a set of frozensets.
set1 = {1, 2}
set2 = {3, 4}
# This will cause a TypeError: unhashable type: 'set'
# set_of_sets = {set1, set2}
# This is the correct way to do it
frozen1 = frozenset(set1)
frozen2 = frozenset(set2)
set_of_frozensets = {frozen1, frozen2}
print(set_of_frozensets)
The output will be: {frozenset({1, 2}), frozenset({3, 4})}
.
What’s Next?
While you may not use it as often as regular sets, the frozenset
is an important tool to have in your knowledge base. It provides an immutable version of a set, making it possible to use set-like data as dictionary keys or as elements within other sets.
This post concludes our introduction to Python’s four primary built-in data structures. We’ve covered lists, tuples, dictionaries, and sets. To solidify everything we’ve learned in this section, it’s time for one final project. In Post #82, we will use the power of sets to analyze the commonalities and differences between two lists of data.
Author

Experienced Cloud & DevOps Engineer with hands-on experience in AWS, GCP, Terraform, Ansible, ELK, Docker, Git, GitLab, Python, PowerShell, Shell, and theoretical knowledge on Azure, Kubernetes & Jenkins. In my free time, I write blogs on ckdbtech.com