Back to Blog
Python

Python frozenset: Immutable Sets Explained

python frozenset: Learn how Python frozenset creates immutable, hashable sets, and when to use them over regular sets for reliable dictionary keys and data integrity.

frozensetimmutable setPython data structureshashable typesset operations
A frozenset represented as an immutable, locked set of unique elements, with a hash symbol indicating its hashability.

The python frozenset type provides an immutable, hashable version of the built-in set. Once created, a frozenset cannot be changed: you cannot add, remove, or modify elements. This immutability makes frozenset hashable, which means it can be used as a dictionary key or as an element of another set—something a regular set cannot do. Understanding when and how to use frozenset helps you write safer, more predictable code when you need to represent a fixed collection of unique items.

What Is a frozenset?

A frozenset is a built-in Python type that behaves like a set but is immutable. It supports the same mathematical set operations—union, intersection, difference, and symmetric difference—but any operation that would modify the set instead returns a new frozenset. Because it is immutable, a frozenset has a fixed hash value, which is computed from its elements. This hashability is the key difference from a regular set and enables frozenset to be used in contexts where hashable objects are required.

Creating a frozenset from an Iterable

You create a frozenset by passing any iterable to the frozenset() constructor. The iterable can be a list, tuple, string, or another set. Duplicate elements are automatically removed, just like with a regular set.

numbers = frozenset([1, 2, 3, 3, 4]) print(numbers) # frozenset({1, 2, 3, 4}) letters = frozenset("hello") print(letters) # frozenset({'h', 'e', 'l', 'o'})

The constructor also accepts a generator or any object that supports iteration. If you pass another frozenset, it returns a copy. There is no way to create an empty frozenset with literal syntax; you must use frozenset() with no arguments.

Set Operations on frozenset

Frozenset supports all the standard set operations, both as methods and as operators. When you use operators like |, &, -, and ^, the result is always a frozenset, regardless of whether the other operand is a set or a frozenset. The same is true for the corresponding methods union(), intersection(), difference(), and symmetric_difference().

a = frozenset([1, 2, 3]) b = frozenset([3, 4, 5]) print(a | b) # frozenset({1, 2, 3, 4, 5}) print(a & b) # frozenset({3}) print(a - b) # frozenset({1, 2}) print(a ^ b) # frozenset({1, 2, 4, 5})

These operations return new frozenset objects. The original frozenset instances remain unchanged, which is consistent with the immutable design.

Hashability and Dictionary Keys

Because frozenset is hashable, it can be used as a key in a dictionary or as an element of another set. This is a common requirement when you need to group data by a collection of values. For example, you might want to map a set of tags to a list of articles that share those tags.

articles_by_tags = {} def add_article(tags, article): key = frozenset(tags) articles_by_tags.setdefault(key, []).append(article) add_article(["python", "tutorial"], "Frozenset guide") add_article(["python", "tutorial"], "Set operations") add_article(["python", "advanced"], "Hashable types") print(articles_by_tags)

Here, the frozenset of tags acts as a dictionary key. If you tried to use a regular set, Python would raise a TypeError because sets are unhashable. This pattern is especially useful when the order of elements in the collection does not matter, since frozenset ignores order.

Practical Use Cases for frozenset

Beyond dictionary keys, frozenset is useful in several other scenarios. It can represent a fixed set of configuration options that should not be modified after initialization. It can also serve as a cache key when you need to memoize a function that takes a collection of arguments. Because frozenset is immutable, it is safe to share across threads without worrying about accidental mutation.

Another application is deduplication of sets. If you have a list of sets that may contain duplicates, you can convert each set to a frozenset and place them in another set to remove duplicates. The hashability of frozenset makes this straightforward.

sets = [{1, 2}, {2, 1}, {3, 4}] unique = {frozenset(s) for s in sets} print(unique) # {frozenset({1, 2}), frozenset({3, 4})}

Performance and Memory Considerations

Frozenset offers some performance advantages in specific situations. Because it is immutable, its hash value can be computed once and cached, though Python does not explicitly guarantee this in the language specification. In practice, repeated hashing of the same frozenset is cheaper than hashing a mutable set would be, because a mutable set's hash would change if the set changed, making it unsuitable for hashing at all.

Memory usage is similar to a regular set of the same size, but frozenset may be slightly more compact in some implementations because it does not need to maintain capacity for future growth. However, the difference is usually negligible for small collections. The main cost is that any modification requires creating a new frozenset, which allocates a new object and copies the elements. If you frequently need to add or remove elements, a regular set is more appropriate.

Limitations and Common Pitfalls

A frozenset cannot be modified in place. Attempting to call methods like add() or remove() will raise an AttributeError. If you need to change the contents, you must create a new frozenset, which can be inefficient in tight loops. Also, because frozenset is a set, it only stores unique elements; if you need to preserve duplicates, you should use a tuple or list.

Another pitfall is that frozenset is not ordered. If you rely on the order of elements, you will be disappointed. The hash value of a frozenset is based on the elements, not their order, so two frozensets with the same elements in different insertion orders are equal and have the same hash. This is usually what you want, but it means you cannot use frozenset as a sequence.

Finally, be careful when using frozenset as a dictionary key if the elements are not hashable themselves. The elements of a frozenset must be hashable, just like those of a regular set. If you try to create a frozenset containing a list, Python will raise a TypeError. This constraint is inherited from the set type and is not specific to frozenset.

When to Choose frozenset Over set

Use frozenset when you need a hashable, immutable collection of unique items. This is common in scenarios where the collection represents a fixed attribute of an object, such as a set of permissions, a set of allowed values, or a set of tags that should not change after creation. If you need to pass a set to a function that might accidentally modify it, wrapping it in a frozenset provides a defensive copy. On the other hand, if you need to perform frequent updates, a regular set is the right choice because it supports amortized O(1) add and remove operations.

The decision also depends on whether you need to use the collection as a dictionary key or as an element of another set. In those cases, frozenset is the only option among the built-in set types. For all other uses, weigh the cost of creating new frozensets against the safety and clarity that immutability provides.

python frozenset: Practical Usage and Code Examples | RYUSLOG DEV