What are some examples of when using a frozenset would be the best option?
frozenset()
objects can be used as dictionary keys and as values inside of set()
and frozenset()
objects, where set
objects cannot. set()
values are mutable and not hashable, frozenset()
values are immutable and are hashable.
They are to set
objects what tuple
objects are to list
objects.
Demo:
>>> s = set([1, 2])
>>> fs = frozenset(s)
>>> adict = {}
>>> adict[s] = 42 # a set as key does not work
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'
>>> adict[fs] = 42 # a frozenset as key works
>>> s.add(s) # a set as value in a set does not work
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'
>>> s.add(fs) # a frozenset as value in a set works
Recent Python versions will optimize the use of a set literal:
if somevar in {'foo', 'bar', 'baz'}:
by storing a frozenset()
constant with the bytecode:
>>> import dis
>>> dis.dis(compile("if somevar in {'foo', 'bar', 'baz'}: pass", '<stdin>', 'exec'))
1 0 LOAD_NAME 0 (somevar)
3 LOAD_CONST 4 (frozenset({'foo', 'baz', 'bar'}))
6 COMPARE_OP 6 (in)
9 POP_JUMP_IF_FALSE 15
12 JUMP_FORWARD 0 (to 15)
>> 15 LOAD_CONST 3 (None)
18 RETURN_VALUE
because the set literal cannot be mutated anyway; this makes using sets to test against very efficient. A regular set()
cannot be stored this way as that would allow you to mutate the constant stored with the byte object.