Разрешенные типы ключей в словарях Python

Раздел: Типы данных -> Словари

Основные типы ключей словаря

Ключами словаря в Python могут быть только неизменяемые (hashable) объекты. Это требование связано с внутренней реализацией словарей, которые используют хеш-таблицы. Хеш объекта должен быть постоянным на протяжении его жизни, поэтому изменяемые типы (списки, множества, словари) не подходят. Наиболее распространенные и эффективные ключи - строки и целые числа. Однако в качестве ключей можно использовать и другие неизменяемые типы: числа с плавающей точкой, кортежи, frozenset, логические значения, None, байтовые строки, а также пользовательские классы, если они правильно реализуют методы __hash__ и __eq__.


d = {
    'строка': 1,
    42: 'число',
    (1, 2): 'кортеж',
    frozenset({1, 2, 3}): 'frozenset',
    True: 'логическое',
    None: 'None',
    b'bytes': 'байты'
}
print(d)

словарь слов python (словарь слов в python)

{'строка': 1, 42: 'число', (1, 2): 'кортеж', frozenset({1, 2, 3}): 'frozenset', True: 'логическое', None: 'None', b'bytes': 'байты'}

Python значение ключа словаря (значение ключа словаря в python)

Типичная ошибка - попытка использовать список или словарь в качестве ключа. В этом случае возникает TypeError: unhashable type: 'list'. Чтобы избежать, преобразуйте список в кортеж, а множество - в frozenset.

Как использовать строки в качестве ключей?

Строки - самый частый выбор для ключей. Они интуитивно понятны и не вызывают проблем с хешированием. Строки чувствительны к регистру, поэтому 'key' и 'Key' - разные ключи. Если требуется регистронезависимость, приводите ключи к единому регистру.


d = {'Name': 'Alice', 'name': 'Bob'}
print(d['name'])  # Bob
# Для регистронезависимости
normalized = {k.lower(): v for k, v in d.items()}
print(normalized.get('name'))  # Bob (последнее значение 'Bob' перезаписало 'Alice')

ключ значение в python (пары ключ-значение в python)

Bob
Bob

получить значение ключа python (получение значения ключа в python)

Проблема: случайное использование ключа с лишними пробелами (например, 'name '). Это может привести к пропуску ключа. Решение - использовать метод strip() при нормализации.

Как использовать числа (int и float) как ключи?

Целые числа работают так же хорошо, как строки. Числа с плавающей точкой (float) также хешируются, но есть риск неточности: 0.1 + 0.2 != 0.3 из-за двоичного представления. Поэтому использование float в качестве ключей может привести к неожиданному поведению.


d = {1: 'one', 2.0: 'two'}
print(d[2.0])  # two
print(d[2])    # KeyError, так как 2 != 2.0?

Python получить ключ (получение ключа словаря в python)

two
KeyError: 2

словарь значения python (словарь значений в python)

Хотя 1 и 1.0 считаются разными ключами (потому что у них разные типы), 2 и 2.0 - разные объекты, хотя математически равны. Для ключей с плавающей точкой рекомендуется использовать Decimal или строковое представление.

Ошибка: TypeError: unhashable type: 'float' никогда не возникает, но путаница с равенством может быть серьёзной. Используйте целые числа или дробные числа, округлённые до известной точности.

Как использовать кортежи как ключи?

Кортежи хешируются, если все их элементы также хешируемы. Это удобно для составных ключей, например, координат (x, y).


points = {(0, 0): 'origin', (1, 2): 'point A', (3, 4): 'point B'}
print(points[(1, 2)])  # point A

список значений словаря python (список значений словаря в python)

point A

удаление словаря python (удаление элемента из словаря в python)

Частая ошибка - кортеж, содержащий изменяемый элемент (например, список). Такой кортеж не может быть ключом:


d = {([1,2], 3): 'error'}  # TypeError: unhashable type: 'list'

добавление в словарь python (добавление в словарь python)

Решение - заменить внутренний список на кортеж или frozenset.

Как использовать frozenset в качестве ключа?

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


d = {frozenset({'a', 'b'}): 'letters'}
print(d[frozenset({'b', 'a'})])  # 'letters', порядок не важен

Python dict add (добавление элемента в словарь python)

letters

Python найти в словаре (поиск ключа в словаре python)

Если попытаться использовать обычное множество (set), будет TypeError. Всегда преобразуйте в frozenset.

Можно ли использовать bool как ключ?

Да, bool - это подтип int, и True/False хешируются как 1 и 0 соответственно. Это может привести к путанице, если в словаре уже есть ключ 0 или 1.


d = {True: 'true', 1: 'one'}
print(d[True])  # one - ключ 1 перезаписал True
print(d[1])     # one

Python dict в строку (преобразование словаря в строку в python)

one
one

Python dict keys (метод dict.keys() в python)

Использование bool как ключа не рекомендуется, если в словаре есть целочисленные ключи, так как True и 1 - один и тот же ключ. Для ясности используйте строки.

Можно ли использовать None, bytes и пользовательские объекты?

NoneType, bytes, а также функции и классы являются хешируемыми. Пользовательские объекты по умолчанию хешируются по id, если явно не переопределены __hash__ и __eq__. Однако если в пользовательском классе определены изменяемые поля, их нужно учитывать.


d = {None: 'empty', b'data': 'binary'}
print(d[None])  # empty

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __hash__(self):
        return hash((self.x, self.y))
    def __eq__(self, other):
        return (self.x, self.y) == (other.x, other.y)

p = Point(1, 2)
d[p] = 'point'
print(d[Point(1, 2)])  # point

создать dict python (создание словаря в python)

empty
point

Без переопределения __hash__ и __eq__ два разных объекта с одинаковыми данными будут считаться разными ключами. Также если объект изменяем, его хеш может измениться после добавления в словарь, что приведет к невозможности его найти. Рекомендуется использовать неизменяемые атрибуты (например, через NamedTuple или dataclass(frozen=True)).

- как удалить элемент из словаря python (удаление элемента из словаря python)
- Python вывести словарь (вывести словарь в python)
- как добавить значение в словарь python (добавление значения в словарь python)

Расширенные примеры использования разных типов ключей:

Пример 1: Кортеж с элементами разных типов

Пример

d = {
    (1, 'a', 3.14): 'mixed',
    (True, None): 'boolean and none'
}
print(d[(1, 'a', 3.14)])  # mixed
print(d[(True, None)])    # boolean and none
mixed
boolean and none

Пример 2: Frozenset с множеством значений

Пример

key = frozenset({10, 20, 30})
d = {key: 'frozenset as key'}
print(d[key])                               # frozenset as key
print(d[frozenset({30, 10, 20})])           # тот же хеш – то же значение
frozenset as key
frozenset as key

Пример 3: Ключ из datetime (неизменяемый объект)

Пример

from datetime import datetime, date
d = {
    datetime(2023, 1, 1): 'new year',
    date.today(): 'today'
}
print(d[datetime(2023, 1, 1)])  # new year
print(d[date.today()])           # today
new year
today

Пример 4: Пользовательский класс с переопределением хеша

Пример

class Color:
    def __init__(self, r, g, b):
        self.r = r
        self.g = g
        self.b = b
    def __hash__(self):
        return hash((self.r, self.g, self.b))
    def __eq__(self, other):
        return (self.r, self.g, self.b) == (other.r, other.g, other.b)
    def __repr__(self):
        return f'Color({self.r},{self.g},{self.b})'

c1 = Color(255, 0, 0)
c2 = Color(0, 255, 0)
d = {c1: 'red', c2: 'green'}
print(d[Color(255, 0, 0)])  # 'red'
print(d)                    # {Color(255,0,0): 'red', Color(0,255,0): 'green'}
red
{Color(255,0,0): 'red', Color(0,255,0): 'green'}

Пример 5: Функция как ключ (редко, но возможно)

Пример

def foo():
    pass
def bar():
    pass
d = {foo: 'function foo', bar: 'function bar'}
print(d[foo])   # function foo
print(d[bar])   # function bar
function foo
function bar

Пример 6: Ключ bytes и bytearray (только bytes)

Пример

d = {b'hello': 'world', b'python': 'language'}
print(d[b'hello'])   # world
# bytearray - изменяемый, не подходит
# d[bytearray(b'hello')]  # TypeError: unhashable type: 'bytearray'
world

Пример 7: Ключи float – проблемы точности

Пример

import math
d = {0.1+0.2: 'sum', 0.3: 'direct'}
print(d)                              # {0.30000000000000004: 'sum', 0.3: 'direct'}
print(d[0.3])                         # direct
print(d.get(0.1+0.2))                  # None? Нет, ключ 0.30000000000000004 не совпадает с 0.3
print(d[0.1+0.2])                     # sum
{0.30000000000000004: 'sum', 0.3: 'direct'}
direct
sum

Чтобы избежать таких расхождений, используйте целые числа или строки.

Типы ключей словаря в Python - comments

En
типы данных ключей словаря python (python)