diff --git a/translations/README-ru.md b/translations/README-ru.md index 382aab8..e032170 100644 --- a/translations/README-ru.md +++ b/translations/README-ru.md @@ -1806,3 +1806,60 @@ NameError: name 'e' is not defined ``` --- + + +### ▶ Загадочное преобразование типов ключей + +```py +class SomeClass(str): + pass + +some_dict = {'s': 42} +``` + +**Результат:** +```py +>>> type(list(some_dict.keys())[0]) +str +>>> s = SomeClass('s') +>>> some_dict[s] = 40 +>>> some_dict # Ожидается 2 разные пары ключ-значение +{'s': 40} +>>> type(list(some_dict.keys())[0]) +str +``` + +#### 💡 Объяснение: + +* И объект `s`, и строка `"s"` хэшируются до одного и того же значения, потому что `SomeClass` наследует метод `__hash__` класса `str`. +* Выражение `SomeClass("s") == "s"` эквивалентно `True`, потому что `SomeClass` также наследует метод `__eq__` класса `str`. +* Поскольку оба объекта хэшируются на одно и то же значение и равны, они представлены одним и тем же ключом в словаре. +* Чтобы добиться желаемого поведения, мы можем переопределить метод `__eq__` в `SomeClass`. + ```py + class SomeClass(str): + def __eq__(self, other): + return ( + type(self) is SomeClass + and type(other) is SomeClass + and super().__eq__(other) + ) + + # При переопределении метода __eq__, Python прекращает автоматическое наследование метода + # __hash__, поэтому его нужно вручную определить + __hash__ = str.__hash__ + + some_dict = {'s':42} + ``` + + **Результат:** + ```py + >>> s = SomeClass('s') + >>> some_dict[s] = 40 + >>> some_dict + {'s': 40, 's': 42} + >>> keys = list(some_dict.keys()) + >>> type(keys[0]), type(keys[1]) + (__main__.SomeClass, str) + ``` + +---