Hashability в Python: почему set.add(set(...)) вызывает TypeError

Hashability в Python: почему set.add(set(...)) вызывает TypeError

@python_quiz

Разберем этот квиз

Кратко: в Python элементы множества (set) должны быть хешируемыми (immutable с реализованным __hash__). frozenset и кортеж — хешируемы, обычный set — нет. Попытка добавить изменяемый set вызовет TypeError, при этом ранее добавленные элементы останутся в множестве.

Условие (фрагмент кода)

python

По шагам — что происходит

  1. s = set() — создаём пустое множество.
  2. s.add(frozenset([1,2])) — frozenset неизменяем и хешируем, добавляется успешно.
  3. s.add((3,4)) — кортеж неизменяем и хешируем, добавляется успешно.
  4. s.add(set([3,4])) — попытка добавить обычный set, который изменяем и не хешируется; Python выбросит TypeError: unhashable type: 'set'. Исключение прервёт выполнение на этой строке.

Важно: исключение не откатывает предыдущие успешные добавления — s будет содержать два первых элемента.

Демонстрация (поведение в Python)

python

Проверка хешируемости:

python

Альтернативы и обходные пути

  • Если нужно хранить множество как элемент множества — используйте frozenset:

`python
s.add(frozenset([3,4]))
`

  • Можно конвертировать в кортеж, если порядок не критичен:

`python
s.add(tuple([3,4]))
`

  • Если хочется хранить изменяемые коллекции в качестве элементов — можно использовать список словарей/списков, но не в set; вместо этого применять структуры данных, которые допускают такие элементы (например список элементов, где элементы могут быть любыми).

Анализ вариантов (коротко)

  • Вариант, утверждающий, что frozenset и кортеж добавятся, а всё выполнится без ошибок — неверен, потому что третья операция вызывает исключение.
  • Вариант с TypeError: unhashable type: 'set' при попытке добавить изменяемый set — описывает реальное поведение.
  • Утверждение, что после исключения множество останется пустым — неверно: первые два добавления уже произошли.
  • Утверждение про TypeError на frozenset — неверно, потому что frozenset хешируем.

Вывод

В множества Python можно добавлять только хешируемые (обычно неизменяемые) объекты: frozenset и tuple — подходят, обычный set — нет. При попытке добавить изменяемый set возникнет TypeError, но ранее добавленные элементы сохранятся. Чтобы хранить "множество внутри множества", либо используйте frozenset, либо конвертируйте во что-то хешируемое.

Report Page