Имеется такой код, где мы делаем 5 записей в словарь:
d = {} d[float('nan')] = 1 d[float('nan')] = 2 d[1.0] = 'float' d[1] = 'int' d[True] = 'bool' print(len(d))
Давайте решим ее. Для ключа словаря нам важны две вещи:
- Хэш hash(key) – ключи с разными хэшами дадут нам разные записи в словаре.
- Равенство ключей – если хэши равны, то проверяется равенство ключей (==), и если и они равны, то считается, что ключ тот же самый – это будет одна и та же запись в словаре.
float(‘nan’)
float('nan')
– создает нам новый объект типа float со значением NaN (not a number – не число). Это специально значение. Оно получается, если результат операции не определен. Например, вычитание бесконечности из бесконечности не даст нам конкретного определенного результата, потому что бесконечность – это не число:
>>> print(float('Inf') - float('Inf')) nan
В соответствии с IEEE 754, такое состояние задаётся через установку показателя степени в зарезервированное значение 11…11, а мантиссы — во что угодно, кроме 0 (зарезервированное значение для машинной бесконечности).
У NaN есть замечательно свойство, что он не равен никакому другому float, даже самому себе или другому NaN.
>>> x = float('nan') >>> x == x False >>> hash(x) 0
Но hash от NaN всегда равен 0. Таким образом, словарь видит, что мы кладем в него ключи с одинаковым хэшем, но не равные между собой. Вывод: мы можем создать сколько угодно ключей с NaN, на вид они одинаковые, даже побитово могут совпадать, но так как каждый NaN не равен другому NaN по определению, то и dict все их считает разными!
>>> d = {} >>> d[float('nan')] = 1 >>> d[float('nan')] = 2 >>> d {nan: 1, nan: 2} >>> d[float('nan')] Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: nan
1, 1.0 и True
Пользуемся той же логикой: сначала проверяем хэши, потом, если они равны, то на равенство:
>>> hash(1), hash(1.0), hash(True) (1, 1, 1) >>> 1 == 1.0 == True True
Все они равны между собой! Поэтому в словаре все эти три ключа будут отвечать ровно одной записи! Посмотрите:
>>> d = {} >>> d[1.0] = 'float' >>> d[1] = 'int' >>> d[True] = 'bool' >>> d {1.0: 'bool'} >>> len(d) 1 >>> d[1] 'bool' >>> d[1.0] 'bool' >>> d[True] 'bool'
Так как первая запись была с 1.0, то и ключ останется типа float, а значение уже будет перезаписано будущими операторами присваивания.
Ответ: 3
У нас в словаре две записи от разных float('nan')
и только одна запись от трех присваиваний 1.0, 1 и True. Итого ответ – 3 (три) записи будет в словаре!
Пусть вас не путает, что в условии задачи было 5 операторов.
Специально для канала @pyway. Подписывайтесь на мой канал в Телеграм @pyway 👈