Ответ 1
Это происходит потому, что True == 1
(и False == 0
, но у вас не было 0
в качестве ключа). Вам придется как-то реорганизовать свой код или данные, потому что dict
считает ключи одинаковыми, если они "равны" (а не is
).
Я создал следующий словарь
exDict = {True: 0, False: 1, 1: 'a', 2: 'b'}
и когда я печатаю exDict.keys()
, ну, он дает мне генератор. Хорошо, поэтому я принуждаю его к списку, и он дает мне
[False, True, 2]
Почему нет 1? Когда я печатаю exDict.items()
, он дает мне
[(False, 1), (True, 'a'), (2, 'b')]
Кто-нибудь может предположить, что происходит здесь? Я в тупике.
Это происходит потому, что True == 1
(и False == 0
, но у вас не было 0
в качестве ключа). Вам придется как-то реорганизовать свой код или данные, потому что dict
считает ключи одинаковыми, если они "равны" (а не is
).
То, что вы видите, это python, принуждающий 1
равняться True
.
Вы увидите, что словарь, который вы печатаете:
False 1
True a
2 b
Если значение a
предназначено для назначения 1
, но вместо этого значение для True
было переназначено на a
.
Согласно Документация Python 3:
Булевский тип является подтипом целочисленного типа, а Булевы значения ведут себя как значения 0 и 1, соответственно, почти во всех контекстах, исключение состоит в том, что при преобразовании в строку, строки "False" или "True" возвращаются соответственно.
Акцент на мой.
Примечание. В python 2.X True
и False
можно переназначить, поэтому это поведение не может быть гарантировано.
Python принимает значение 1 как True
. И тип Boolean является подтипом целочисленного типа
In [1]: a = {}
In [2]: a[True] = 0
In [3]: 1 in a.keys()
Out[3]: True
Если вы вставляете пару ключ-значение в проверку 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}
Единственное, что важно - помнить, что словарные ключи сохраняются равными, если объекты и их хэш равны.