You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
> должен быть один - и желательно только один - очевидный способ сделать это.
3531
3531
3532
3532
---
3533
+
3534
+
3535
+
### ▶ Замедляем поиск по `dict` *
3536
+
<!-- Example ID: c9c26ce6-df0c-47f7-af0b-966b9386d4c3 --->
3537
+
```py
3538
+
some_dict = {str(i): 1 for i in range(1_000_000)}
3539
+
another_dict = {str(i): 1 for i in range(1_000_000)}
3540
+
```
3541
+
3542
+
**Результат:**
3543
+
```py
3544
+
>>> %timeit some_dict['5']
3545
+
28.6 ns ± 0.115 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
3546
+
>>> some_dict[1] = 1
3547
+
>>> %timeit some_dict['5']
3548
+
37.2 ns ± 0.265 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
3549
+
3550
+
>>> %timeit another_dict['5']
3551
+
28.5 ns ± 0.142 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
3552
+
>>> another_dict[1] # Пытаемся получить значение по несуществующему ключу
3553
+
Traceback (most recent call last):
3554
+
File "<stdin>", line 1, in <module>
3555
+
KeyError: 1
3556
+
>>> %timeit another_dict['5']
3557
+
38.5 ns ± 0.0913 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
3558
+
```
3559
+
Почему одни и те же выражения становятся медленнее?
3560
+
3561
+
#### 💡 Объяснение:
3562
+
3563
+
+ В CPython есть общая функция поиска по словарю, которая работает со всеми типами ключей (`str`, `int`, любой объект ...), и специализированная для распространенного случая словарей, состоящих только из `str`-ключей.
3564
+
+ Специализированная функция (названная `lookdict_unicode` в [исходный код CPython](https://github.com/python/cpython/blob/522691c46e2ae51faaad5bbbce7d959dd61770df/Objects/dictobject.c#L841)) знает, что все существующие ключи (включая искомый ключ) являются строками, и использует более быстрое и простое сравнение строк для сравнения ключей, вместо вызова метода `__eq__`.
3565
+
+ При первом обращении к экземпляру `dict` с ключом, не являющимся `str`, он модифицируется, чтобы в дальнейшем для поиска использовалась общая функция.
3566
+
+ Этот процесс не обратим для конкретного экземпляра `dict`, и ключ даже не обязательно должен существовать в словаре. Поэтому попытка неудачного поиска имеет тот же эффект.
0 commit comments