Вопрос-Ответ

Why can't I use a list as a dict key in python? Exactly what can and cannot be used, and why?

Почему я не могу использовать список в качестве ключа dict в python? Что именно можно и чего нельзя использовать и почему?

Я обнаружил, что все следующие действия допустимы:

>>> d = {}
>>> d[None] = 'foo'
>>> d[(1, 3)] = 'baz'

В качестве ключа 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 разрешил использовать списки в качестве ключей, скажем, используя их расположение в памяти в качестве хэша?

Переведено автоматически
Ответ 1

В Python wiki есть хорошая статья на эту тему: Почему списки не могут быть ключами словаря. Как объяснено там:


Что пошло бы не так, если бы 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]]? Он имеет те же значения, но это другой список?

В конечном счете, удовлетворительного ответа нет:


  • Если единственный работающий ключ - это исходный ключ, то доступ к значению становится невозможным без сохранения ссылки на исходный ключ (и наличия доступа к нему)



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



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



2024-01-01 12:58 python list dictionary