В качестве ключа dict можно использовать даже модуль:
>>> import sys >>> d[sys] = 'bar'
Однако список не может, как и кортеж, содержащий список:
>>> d[[2]] = 'spam' Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unhashable type: 'list' >>> d[(1, [3])] = 'qux' Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unhashable type: 'list'
Почему хранение списка внутри кортежа означает, что он больше не может быть ключом dict? В конце концов, я мог бы так же легко "спрятать" список внутри модуля (и действительно, например, sys.path это уже список).
У меня было смутное представление о том, что ключ должен быть "хэшируемым", но у меня нет подробного понимания того, что это значит, или почему существует такое ограничение. Что пошло бы не так, если бы Python разрешил использовать списки в качестве ключей, скажем, используя их расположение в памяти в качестве хэша?
Что пошло бы не так, если бы Python разрешил использовать списки в качестве ключей, скажем, используя их расположение в памяти в качестве хэша?
Это может вызвать некоторое неожиданное поведение. Списки обычно обрабатываются так, как если бы их значение было получено из значений их содержимого, например, при проверке равенства (in-). Многие - по понятным причинам - ожидают, что вы можете использовать любой список [1, 2] для получения одного и того же ключа, где вам придется хранить точно такой же объект list . Но поиск по значению прерывается, как только список, используемый в качестве ключа, изменяется, а поиск по идентификатору требует отслеживания именно этого объекта list, что не является обычным требованием для работы со списками.
Другие объекты, такие как modules и object , в любом случае имеют гораздо большее значение для своей объектной идентичности (когда у вас в последний раз вызывались два разных модульных объектаsys?), И в любом случае сравниваются по этому параметру. Поэтому менее удивительно - или даже ожидаемо - что при использовании в качестве ключей dict они также сравниваются по идентификатору.
Ответ 2
Почему я не могу использовать список в качестве ключа dict в Python?
>>> d = {repr([1,2,3]): 'value'} {'[1, 2, 3]': 'value'}
Как объяснялось другими здесь, вы действительно не можете. Однако вы можете использовать его строковое представление вместо этого, если вы действительно хотите использовать свой список.
Ответ 3
Список можно преобразовать в кортеж, который можно использовать в качестве ключа dict: например
d = {tuple([1,2,3]): 'value'}
Ответ 4
Проблема в том, что кортежи неизменяемы, а списки - нет. Рассмотрим этот пример.:
d = {} li = [1,2,3] d[li] = 5 li.append(4)
Что должно d[li] возвращать? Это тот же список? Как насчет d[[1,2,3]]? Он имеет те же значения, но это другой список?
В конечном счете, удовлетворительного ответа нет:
Если единственный работающий ключ - это исходный ключ, то доступ к значению становится невозможным без сохранения ссылки на исходный ключ (и наличия доступа к нему)
Если работает только ключ с одинаковым содержимым, то изменение ключа изменяет способ работы поиска; и любой другой код, который имеет ссылку на этот список, может изменить его, возможно, вызвав сюрприз позже.
Если оба варианта работают, то у вас очень разные ключи, сопоставленные одному и тому же значению, что более чем немного удивительно.