A frozenset in Python is essentially an immutable version of a regular set. Like a set, it is an unordered collection of unique items. However, the key difference is that once a frozenset is created, you cannot change it—you cannot add or remove elements.
Why Use a frozenset? The Concept of "Hashable"
Because it's immutable, a frozenset is hashable. This is a critical concept in Python. It means that an object has a hash value that never changes during its lifetime, which allows it to be used as a reliable key in a dictionary or as an element inside another set.
You cannot use a regular, mutable set as a dictionary key because its contents (and therefore its hash value) could change. A frozenset solves this problem.
Operations and Methods
A frozenset supports all the same methods and operations as a regular set, as long as they do not modify the set.
- Supported Operations: You can perform mathematical set operations like union (|), intersection (&), difference (-), and symmetric difference (^).
- Supported Methods: It has methods that return a new set, such as .union(), .intersection(), .difference(), and methods for comparison like .issubset() and .isdisjoint().
- Unsupported Methods: It lacks any methods that would change the set in place, such as .add(), .remove(), .discard(), .pop(), and .update().
# --- 1. Frozenset Creation ---
# A frozenset is created using the frozenset() constructor.
# It takes an iterable (like a list, tuple, or set) as an argument.
my_list = [1, 2, 3, 3, 4] # Note the duplicate '3'
frozen_numbers = frozenset(my_list)
print("--- Frozenset Creation ---")
print(f"Original list: {my_list}")
print(f"Created frozenset: {frozen_numbers}") # Duplicates are removed
# --- 2. Immutability Demonstration ---
# The key feature of a frozenset is that it cannot be changed.
print("\n--- Immutability ---")
# The following lines would cause an AttributeError if uncommented:
# frozen_numbers.add(5)
# frozen_numbers.remove(1)
print("Frozensets are immutable. You cannot add or remove elements.")
# --- 3. Set Operations ---
# Frozensets support all standard, non-modifying set operations.
set_a = frozenset([1, 2, 3, 4])
set_b = frozenset([3, 4, 5, 6])
print("\n--- Set Operations ---")
print(f"Set A: {set_a}")
print(f"Set B: {set_b}")
# Union (|): All unique elements from both sets.
print(f"Union (A | B): {set_a | set_b}")
# Intersection (&): Elements that are in both sets.
print(f"Intersection (A & B): {set_a & set_b}")
# Difference (-): Elements in A but not in B.
print(f"Difference (A - B): {set_a - set_b}")
# Symmetric Difference (^): Elements in either A or B, but not both.
print(f"Symmetric Difference (A ^ B): {set_a ^ set_b}")
# --- 4. Frozenset Methods ---
# It supports methods that don't change the set.
print("\n--- Frozenset Methods ---")
print(f"A.isdisjoint(B): {set_a.isdisjoint(set_b)}") # False, because they share 3 and 4
print(f"frozenset([1, 2]).issubset(A): {frozenset([1, 2]).issubset(set_a)}") # True
# --- 5. Built-in Functions with Frozensets ---
print("\n--- Built-in Functions ---")
print(f"Length of Set A: {len(set_a)}")
print(f"Sum of Set A: {sum(set_a)}")
print(f"Max of Set A: {max(set_a)}")
# --- 6. Key Use Case: Dictionary Keys ---
# Because frozensets are immutable and hashable, they can be used as dictionary keys.
# A regular set cannot be used in this way.
permissions = {
frozenset(["read"]): "Read-only access",
frozenset(["read", "write"]): "Read and write access",
frozenset(["read", "write", "execute"]): "Full access"
}
user_permissions = frozenset(["write", "read"])
print("\n--- Use Case: Dictionary Keys ---")
print(f"Access level for {user_permissions}: {permissions[user_permissions]}")