Python frozenset() Function

Spread the love

A frozenset is, essentially, an immutable version of a Python set. While a set is mutable and allows for modification after its creation, a frozenset is hashable and does not permit any modifications after it’s created. This characteristic makes frozensets useful in scenarios where immutability is a necessity.

Syntax:

frozenset([iterable])

Parameters:

iterable (Optional) – the iterable which contains elements to initialize the frozenset with.

Return value:

The frozenset() function returns an immutable frozenset initialized with elements from the given iterable. If no parameters are passed, it returns an empty frozenset.

Creating a frozenset

Create a frozenset from a List:

Lists are among the most commonly used data structures in Python. They are ordered collections of items, which can be of any type and can also contain duplicate values. The items in a list are indexed (starting from 0) and can be accessed using their indices. They are defined by enclosing their values in square brackets [].

For example, consider the following list:

fruits_list = ["apple", "banana", "cherry", "apple"]

Here, fruits_list is a list that contains four elements, with “apple” appearing twice.

Now, if we want to convert this list into a frozenset, we use the frozenset() function. When a list is passed as an argument to the frozenset() function, it returns a new frozenset object containing the unique items from the list. The order of items in a frozenset is not guaranteed to be preserved, since sets (and by extension, frozensets) are inherently unordered collections.

Here’s how you can create a frozenset from the above list:

fruits_frozenset = frozenset(fruits_list)
print(fruits_frozenset)

Output:

frozenset({'banana', 'apple', 'cherry'})

A few things to note:

  1. Removal of Duplicates: You’ll observe that in the output, the duplicate “apple” from the original list is removed. This is because sets and frozensets in Python only store unique values.
  2. Unordered: The order in the frozenset might not match the order in the original list. In the case of our fruits_frozenset, there’s no guarantee that “apple” will come before “banana” or “cherry”.
  3. Immutability: Once the frozenset is created, you can’t add or remove elements from it. This is in contrast to the original list, which is mutable.

This conversion is particularly useful in scenarios where you want to deduplicate a list or need an immutable version of a set for operations like dictionary key storage, set comparisons, etc.

Create a frozenset from a Tuple:

Tuples, like lists, are another type of ordered collection in Python. However, unlike lists, they are immutable, meaning once defined, the elements within cannot be altered, added, or removed. Tuples are defined by enclosing their values in parentheses ().

For instance, let’s consider the following tuple:

colors_tuple = ("red", "green", "blue", "red")

Here, colors_tuple is a tuple containing four elements, with “red” appearing twice.

When you want to convert this tuple into a frozenset, you can make use of the frozenset() function. When passed a tuple as its argument, the function returns a new frozenset object with the unique items from the tuple. Remember, the order of items in a frozenset isn’t guaranteed to be preserved because sets and frozensets are intrinsically unordered collections.

Here’s the conversion of the above tuple into a frozenset:

colors_frozenset = frozenset(colors_tuple)
print(colors_frozenset)

Output:

frozenset({'blue', 'green', 'red'})

In practical scenarios, the conversion of a tuple to a frozenset can be useful when you start with ordered data but eventually require the set functionalities like union, intersection, and especially immutability, without concern for the order of data.

Create a frozenset from a String:

A string in Python is essentially a sequence of characters. Each character in the string can be accessed by its index (starting from 0). Strings in Python are immutable, meaning their contents cannot be altered after they’ve been created. They are defined by enclosing characters within single ('), double ("), or triple (''' or """) quotes.

For example, consider the following string:

word = "banana"

Here, word is a string containing six characters, with the character “a” appearing three times.

To convert this string into a frozenset, you can use the frozenset() function. When a string is passed to the frozenset() function, each character from the string becomes an element of the frozenset. The resulting frozenset will contain only the unique characters from the string, since sets and frozensets inherently store only unique values.

Here’s how you can create a frozenset from the above string:

word_frozenset = frozenset(word)
print(word_frozenset)

Output:

frozenset({'b', 'a', 'n'})

Converting a string to a frozenset is particularly useful when you want to quickly deduce the unique characters in a string, or when you want to perform set operations on strings, such as checking the common characters between two words.

Properties of frozenset

Immutability:

Immutability, in the context of programming and data structures, refers to the unchangeable nature of an object once it’s been created. When we say an object is immutable, it means that its state or value cannot be modified after its creation. This stands in contrast to mutable objects, which can be changed or modified post-creation.

Python offers both mutable (like lists and sets) and immutable (like strings, tuples, and frozensets) data types. Each comes with its own set of advantages and use cases.

Understanding Immutability in frozenset :

As for frozenset, its primary characteristic is immutability. What this means in practical terms is:

No Addition: You cannot add elements to a frozenset after its creation. In other set types, you would use the add() method for this purpose. However, the frozenset lacks this method altogether.

fs = frozenset([1, 2, 3])
fs.add(4)  # This would raise an AttributeError

No Removal: Similarly, removing elements is also not possible. Whereas with mutable sets, you’d use the remove() or discard() methods, attempting this with a frozenset would result in an error.

fs.remove(1)  # This would raise an AttributeError

No Modification: Beyond just adding or removing, you cannot modify a frozenset in any way that would change its content. Any operation that would typically alter the state of a set will not work with a frozenset.

Why Immutability Matters:

  1. Predictability: Immutable objects, by definition, are more predictable since you know they won’t change. This can simplify logic and debugging in certain scenarios.
  2. Safety: In concurrent programming, multiple threads can interact with data simultaneously. With mutable data structures, there’s a risk of one thread modifying the data while another is using it, leading to unpredictable results. Immutable structures eliminate this risk.
  3. Hashability: In Python, only immutable objects can be used as dictionary keys. This is because the hash value of the object should remain constant throughout its lifetime. Since frozenset is immutable, it is hashable and can be used as a key in dictionaries, unlike regular sets.
  4. Functional Programming: Immutability aligns well with the principles of functional programming, where functions don’t have side effects and data isn’t modified once created.

The immutability of frozenset can be seen as both a strength and a limitation, depending on the use case. It offers certain advantages like predictability, safety in concurrent scenarios, and the ability to be used as dictionary keys. However, for situations that require dynamic modification of the set, a regular mutable set would be more appropriate. Knowing when to use which comes with understanding the problem at hand and the benefits that immutability can offer in that context.

Hashable:

What is Hashability?

In Python, for an object to be used as a dictionary key, it needs to be hashable. A hashable object has a hash value which never changes during its lifetime, ensuring a constant association between the key and its value in the dictionary. This hash value is an integer derived from the value of the object and is used internally by the dictionary to quickly locate the object.

To be hashable, an object must satisfy two conditions:

  1. It should have a hash value which remains constant throughout its lifetime. You can retrieve this value using Python’s built-in hash() function.
  2. It should be comparable using equality, meaning you can determine if two instances of the object are equal (a == b).

Immutable data types in Python like integers, floats, strings, and tuples are hashable (unless they contain unhashable items), making them valid candidates for dictionary keys.

Frozensets and Hashability:

Since frozenset is immutable, its content cannot change after creation. This ensures that its hash value remains constant, making it hashable.

For example, you can find the hash value of a frozenset:

fs = frozenset([1, 2, 3])
print(hash(fs))  #output -272375401224217160

The immutability ensures that the hash value derived from the frozenset stays the same throughout its existence, thus adhering to the key requirement of hashability.

Sets vs. Frozensets:

On the other hand, a regular set in Python is mutable. You can add or remove elements from it after its creation. Because of this mutability, sets cannot guarantee a constant hash value throughout their lifetime, which renders them unhashable and hence, unsuitable as dictionary keys.

For example, trying to get the hash of a regular set:

s = {1, 2, 3}
print(hash(s))  # This would raise a TypeError

Practical Implications:

Being hashable allows frozenset to be used as keys in dictionaries, which can be useful in various scenarios. For instance, you might want to create a dictionary that maps a specific combination of items (represented as a frozenset) to a particular value. This is especially handy when the order of items doesn’t matter but their combination does.

data = {
    frozenset(['apple', 'banana']): 'Fruit combo 1',
    frozenset(['orange', 'pineapple']): 'Fruit combo 2'
}

print(data[frozenset(['banana', 'apple'])])  # Outputs: 'Fruit combo 1'

Hashability is a fundamental property in Python, especially when it comes to using objects as dictionary keys. The immutable nature of frozenset ensures its hashability, giving it an advantage over regular sets in contexts where sets need to be used as dictionary keys.

Methods Available with frozenset

Since frozenset is immutable, the number of methods it supports is fewer than the mutable set. However, it does support non-modifying set operations. Below are the methods associated with frozenset:

frozenset.copy( ) :

Returns a shallow copy of the frozenset. This might seem redundant as frozensets are immutable, but it can be useful in certain contexts to ensure you’re working with a distinct object.

fs = frozenset([1, 2, 3])
new_fs = fs.copy()
print(new_fs)  # Outputs: frozenset({1, 2, 3})

frozenset.difference(*others):

Returns a new frozenset with elements from the original frozenset that are not present in the other specified sets (*others). It’s the equivalent of the set difference operation.

fs1 = frozenset([1, 2, 3, 4])
fs2 = frozenset([3, 4, 5, 6])
result = fs1.difference(fs2)
print(result)  # Outputs: frozenset({1, 2})

frozenset.intersection(*others):

Returns a new frozenset with elements that are common to all the sets, including the original one and the ones specified as arguments.

fs1 = frozenset([1, 2, 3, 4])
fs2 = frozenset([2, 3, 4, 5])
result = fs1.intersection(fs2)
print(result)  # Outputs: frozenset({2, 3, 4})

frozenset.isdisjoint(other):

Returns True if the frozenset and the other specified set have no elements in common.

fs1 = frozenset([1, 2, 3])
fs2 = frozenset([4, 5, 6])
print(fs1.isdisjoint(fs2))  # Outputs: True

frozenset.issubset(other):

Returns True if every element of the frozenset is present in the other specified set.

fs1 = frozenset([1, 2])
fs2 = frozenset([1, 2, 3, 4])
print(fs1.issubset(fs2))  # Outputs: True

frozenset.issuperset(other):

Returns True if every element of the other specified set is present in the frozenset.

fs1 = frozenset([1, 2, 3, 4])
fs2 = frozenset([2, 3])
print(fs1.issuperset(fs2))  # Outputs: True

frozenset.symmetric_difference(other):

Returns a new frozenset with elements that are either in the frozenset or in the other specified set, but not in both.

fs1 = frozenset([1, 2, 3, 4])
fs2 = frozenset([3, 4, 5, 6])
result = fs1.symmetric_difference(fs2)
print(result)  # Outputs: frozenset({1, 2, 5, 6})

frozenset.union(*others):

Returns a new frozenset with elements from the frozenset and all the other specified sets.

fs1 = frozenset([1, 2])
fs2 = frozenset([3, 4])
result = fs1.union(fs2)
print(result)  # Outputs: frozenset({1, 2, 3, 4})

While the frozenset lacks methods that modify its content (like add or remove which are available for set), it supports a wide range of set operations that don’t change the original data but return new frozenset objects. These methods enable developers to perform various operations, such as finding intersections, unions, or differences, and checking relationships between different sets, all while maintaining the immutability guarantee of the frozenset.

Conclusion

The frozenset() function in Python provides a way to create immutable sets which have applications in various scenarios ranging from data integrity assurance to graph algorithms. It’s a valuable tool in the Python developer’s toolkit, especially when immutability and data integrity are of concern.

Leave a Reply