Словарь Python не имеет всех назначенных ключей или элементов

Я создал следующий словарь

exDict = {True: 0, False: 1, 1: 'a', 2: 'b'}

и когда я печатаю exDict.keys(), ну, он дает мне генератор. Хорошо, поэтому я принуждаю его к списку, и он дает мне

[False, True, 2]

Почему нет 1? Когда я печатаю exDict.items(), он дает мне

[(False, 1), (True, 'a'), (2, 'b')]

Кто-нибудь может предположить, что происходит здесь? Я в тупике.

Ответ 1

Это происходит потому, что True == 1False == 0, но у вас не было 0 в качестве ключа). Вам придется как-то реорганизовать свой код или данные, потому что dict считает ключи одинаковыми, если они "равны" (а не is).

Ответ 2

То, что вы видите, это python, принуждающий 1 равняться True.

Вы увидите, что словарь, который вы печатаете:

False  1
True   a
2      b

Если значение a предназначено для назначения 1, но вместо этого значение для True было переназначено на a.

Согласно Документация Python 3:

Булевский тип является подтипом целочисленного типа, а Булевы значения ведут себя как значения 0 и 1, соответственно, почти во всех контекстах, исключение состоит в том, что при преобразовании в строку, строки "False" или "True" возвращаются соответственно.

Акцент на мой.

Примечание. В python 2.X True и False можно переназначить, поэтому это поведение не может быть гарантировано.

Ответ 3

Python принимает значение 1 как True. И тип Boolean является подтипом целочисленного типа

In [1]: a = {}

In [2]: a[True] = 0

In [3]: 1 in a.keys()
Out[3]: True

Ответ 4

Если вы вставляете пару ключ-значение в проверку dict python, если ключ уже существует, и если он существует, он заменит текущее значение.

Эта проверка делает что-то вроде этого:

def hash_and_value_equal(key1, key2):
    return hash(key1) == hash(key2) and key1 == key2

Значит, не только значения должны быть равны, но также и их hash. К несчастью для вас True и 1, но также False и 0 будут считаться равными ключами:

>>> hash_and_value_equal(0, False)
True

>>> hash_and_value_equal(1, True)
True

и поэтому они заменяют значение (, но не ключ):

>>> a = {1: 0}
>>> a[True] = 2
>>> a
{1: 2}

>>> a = {False: 0}
>>> a[0] = 2
>>> a
{False: 2}

Я показал случай добавления ключа вручную, но сделанные шаги одинаковы при использовании dict literal:

>>> a = {False: 0, 0: 2}
>>> a
{False: 2}

или dict -builtin:

>>> a = dict(((0, 0), (False, 2)))
>>> a
{0: 2}

Это может быть очень важно, если вы пишете собственные классы и хотите использовать их в качестве потенциальных ключей внутри словарей. В зависимости от вашей реализации __eq__ и __hash__ они будут и не будут заменять значения одинаковых, но не идентичных ключей:

class IntContainer(object):
    def __init__(self, value):
        self.value = value

    def __eq__(self, other):
        return self.value == other

    def __hash__(self):
        # Just offsetting the hash is enough because it also checks equality
        return hash(1 + self.value)

>>> hash_equal(1, IntContainer(1))
False

>>> hash_equal(2, IntContainer(1))
False

Таким образом, они не заменят существующие целые ключи:

>>> a = {1: 2, IntContainer(1): 3, 2: 4}
>>> a
{1: 2, <__main__.IntContainer at 0x1ee1258fe80>: 3, 2: 4}

или что-то, что считается идентичным:

class AnotherIntContainer(IntContainer):
    def __hash__(self):
        # Not offsetted hash (collides with integer)
        return hash(self.value)

>>> hash_and_value_equal(1, AnotherIntContainer(1))
True

Теперь они заменят целые ключи:

>>> a = {1: 2, AnotherIntContainer(1): 5}
>>> a
{1: 5}

Единственное, что важно - помнить, что словарные ключи сохраняются равными, если объекты и их хэш равны.