Использование Tuples и Frozensets в качестве ключей словаря в Python

Tuples и frozensets — это неизменяемые т. е. неизменяемые версии списков и наборов соответственно. Одним из преимуществ неизменности является то, что эти структуры данных хешируются. Таким образом, для кортежа и замороженного набора может быть уникальный хэш. Это также означает, что их можно использовать в качестве ключей в словаре, в то время как их изменяемые аналоги, то есть списки и наборы, нельзя использовать в качестве ключей словаря.

Почему они хешируются?

Поскольку эти типы данных являются неизменяемыми, это означает, что после их создания значения не могут быть изменены, и поэтому значение хеш-функции всегда будет одним и тем же.

>>> my_set = set([1, 2, 1, 3])
>>> hash(my_set) # set cannot be hashed!
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'
>>> my_frozenset = frozenset([1, 2, 1, 3])
>>> hash(my_frozenset)
-272375401224217160
>>> another_frozenset = frozenset([1, 2, 3, 1])
>>> hash(another_frozenset) # Hash value should be same as before as elements are the same
-272375401224217160
>>> my_tuple = (1, 2, 1, 3)
>>> hash(my_tuple)
-3261335203891832775
>>> my_tuple = (1, 2, 3, 1)
>>> hash(my_tuple) # hash values of the tuples are different as the order of elements are different
-3132950713063864564

Когда использовать кортежи и замороженные наборы в качестве ключей словаря?

При использовании в словаре использование этих типов имеет значение.

Если порядок элементов в ключе имеет значение, то в качестве ключа словаря следует использовать кортежи.

Если порядок элементов в ключе не имеет значения, а дубликаты можно игнорировать, то в качестве ключа словаря можно использовать замороженный набор.

>>> dict1 = {(1,2): "ab", (2,1):"cd"}
>>> (1,2) in dict1 # Check if the tuple exists in the dictionary dict1
True
>>> dict1 # 2 different elements as order of elements in a Tuple matters
{(1, 2): 'ab', (2, 1): 'cd'}

>>> dict3={frozenset([1,2]):"ab"}
>>> dict3[frozenset([2,1,1])]="cd" # Update existing element in the dictionary
>>> dict3
{frozenset({1, 2}): 'cd'}
>>> frozenset([2,1]) in dict3
True
>>> frozenset([1,2]) in dict3
True
>>> frozenset([1,2,2,1]) in dict3 # Order of items and duplicates are ignored
True