Что на самом деле означает «неизменяемые элементы» при создании набора? - PullRequest
0 голосов
/ 01 августа 2020

Я тестирую фрагмент кода следующим образом:

>>>s = set(([1, (2, 3)])) #OK                  # 1
>>>s
{(1, (2, 3))} # put a tuple as set element

>>>s = set([(1, [2, 3])]) #error               # 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

>>>s = set([[1, 2]]) #error                    # 3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

Когда я помещаю кортеж в качестве элемента набора (в 1), он работает. Но если я поместил кортеж, содержащий список, как элемент (в 2) или просто поместил список (в 3) в элемент набора, это пошло не так. Я знаю, что кодирование типа list = [1,2]; s = set([list]) запрещено, потому что мы можем изменить list позже. Но я просто не понимаю, поскольку [1,2] сам по себе неизменен и не изменится, почему я не могу кодировать s = set([[1,2]]).

Ответы [ 2 ]

0 голосов
/ 01 августа 2020

Вы не можете вставлять изменяемые объекты в набор, так же как вы не можете использовать их как ключ dict.

Вы можете использовать только неизменяемые объекты из-за внутренней реализации, которая использует hash(obj) для идентификации объекты, которые вы вставляете. Если бы вы могли вставлять изменяемые объекты, они могли бы изменить значение ha sh (obj), что заставило бы set, dict, et c вести себя неожиданно некорректно.

[1, 2], даже если он введен как литерал списка, по-прежнему является списком и, следовательно, изменяемым объектом.

Учтите следующее:

x = set([[1, 2]])
next(iter(x)).append(3)
0 голосов
/ 01 августа 2020

Обратите внимание, что в сообщении об ошибке написано «нехешируемый тип: 'список'». Это отличается от неизменяемого и изменяемого. Давайте посмотрим на более простой пример, который вызывает ту же ошибку:

>>> s = set()
>>> s.add(1)
>>> s.add([2, 3])
>>> s
{1}
>>> s.add((2, 3))
>>> s
{(2, 3), 1}
>>> s.add([2, 3])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>>

Итак, здесь мы видим, что мы можем добавить целое число 1 в набор, но не список [2, 3], потому что список не хэшируемый. . Это связано с тем, как set хранит и извлекает значения. Класс set требует, чтобы он мог вызывать hash() для своих элементов.

Теперь ваша версия:

>>>s = set([1,(2,3)]) #OK                   1
>>>s
{1,(2.3)} # Note: the output in your original question has an extra set of parentheses

Когда вы вызываете set() таким образом, он добавляет элементы данный список в набор. Конечный результат такой же, как при вызове add() для каждого элемента.

Теперь, если мы попробуем:

>>>s = set([1,[2,3]])

Мы не должны удивляться ошибке, потому что мы пытаемся добавить список к набору.

...