← Назад к вопросам

Что такое служебный метод dict?

1.3 Junior🔥 111 комментариев
#Python

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Служебные методы dictionary (dict) в Python

Служебные методы словаря — это встроенные методы, начинающиеся с двойного подчёркивания (__method__), которые определяют поведение словаря при выполнении стандартных операций. Они вызываются автоматически при использовании встроенных функций и операторов.

Основные служебные методы

1. __init__()

Инициализирует новый словарь

dict1 = {}  # Вызывает __init__() неявно
dict2 = dict()  # Явно вызывает __init__()
dict3 = {"a": 1, "b": 2}  # Инициализация со значениями

class MyDict(dict):
    def __init__(self, *args, **kwargs):
        print("MyDict инициализирован")
        super().__init__(*args, **kwargs)

md = MyDict(a=1, b=2)  # Выведет: MyDict инициализирован

2. __getitem__(key)

Получение значения по ключу через dict[key]

my_dict = {"a": 1, "b": 2}
value = my_dict["a"]  # Вызывает __getitem__("a")
print(value)  # 1

# Пользовательская реализация
class SafeDict(dict):
    def __getitem__(self, key):
        print(f"Доступ к ключу: {key}")
        return super().__getitem__(key)

sd = SafeDict({"x": 10})
print(sd["x"])  # Выведет: Доступ к ключу: x, затем 10

3. __setitem__(key, value)

Установка значения через dict[key] = value

my_dict = {}
my_dict["name"] = "Alice"  # Вызывает __setitem__("name", "Alice")

# Пользовательская реализация
class ValidatedDict(dict):
    def __setitem__(self, key, value):
        if not isinstance(value, int):
            raise ValueError(f"Значение должно быть int, получено {type(value)}")
        super().__setitem__(key, value)

vd = ValidatedDict()
vd["age"] = 25  # OK
# vd["age"] = "twenty"  # ValueError!

4. __delitem__(key)

Удаление пары ключ-значение через del dict[key]

my_dict = {"a": 1, "b": 2}
del my_dict["a"]  # Вызывает __delitem__("a")
print(my_dict)  # {"b": 2}

# Пользовательская реализация
class LoggingDict(dict):
    def __delitem__(self, key):
        print(f"Удаляем ключ: {key}")
        super().__delitem__(key)

ld = LoggingDict({"x": 1, "y": 2})
del ld["x"]  # Выведет: Удаляем ключ: x

5. __len__()

Получение количества пар ключ-значение через len(dict)

my_dict = {"a": 1, "b": 2, "c": 3}
size = len(my_dict)  # Вызывает __len__()
print(size)  # 3

# Пользовательская реализация
class CountingDict(dict):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.access_count = 0
    
    def __len__(self):
        self.access_count += 1
        print(f"Запрос размера (запрос #{self.access_count})")
        return super().__len__()

cd = CountingDict({"a": 1})
print(len(cd))  # Выведет: Запрос размера (запрос #1), затем 1
print(len(cd))  # Выведет: Запрос размера (запрос #2), затем 1

6. __contains__(key)

Проверка наличия ключа через key in dict

my_dict = {"a": 1, "b": 2}
print("a" in my_dict)  # Вызывает __contains__("a"), выведет True
print("c" in my_dict)  # Вызывает __contains__("c"), выведет False

# Пользовательская реализация
class CaselessDict(dict):
    def __contains__(self, key):
        # Поиск без учёта регистра
        return any(k.lower() == key.lower() for k in self.keys())

cd = CaselessDict({"Name": "Alice", "Age": 25})
print("name" in cd)  # True
print("NAME" in cd)  # True
print("age" in cd)   # True

7. __iter__()

Получение итератора через for key in dict или iter(dict)

my_dict = {"a": 1, "b": 2, "c": 3}
for key in my_dict:  # Вызывает __iter__()
    print(key)

# Эквивалентно:
iterator = iter(my_dict)  # Явно вызывает __iter__()
for key in iterator:
    print(key)

# Пользовательская реализация (обратный порядок)
class ReverseDict(dict):
    def __iter__(self):
        return iter(reversed(list(super().keys())))

rd = ReverseDict({"a": 1, "b": 2, "c": 3})
for key in rd:
    print(key)  # Выведет: c, b, a

8. __eq__(other)

Сравнение словарей через dict1 == dict2

dict1 = {"a": 1, "b": 2}
dict2 = {"a": 1, "b": 2}
dict3 = {"a": 1, "b": 3}

print(dict1 == dict2)  # True, вызывает __eq__()
print(dict1 == dict3)  # False

9. __repr__() и __str__()

Текстовое представление словаря

my_dict = {"a": 1, "b": 2}
print(repr(my_dict))  # {"a": 1, "b": 2}
print(str(my_dict))   # {"a": 1, "b": 2}

# Пользовательская реализация
class PrettyDict(dict):
    def __repr__(self):
        items = [f"  {k}: {v}" for k, v in self.items()]
        return "{\n" + ",\n".join(items) + "\n}"

pd = PrettyDict({"name": "Alice", "age": 25})
print(pd)
# Выведет:
# {
#   name: Alice,
#   age: 25
# }

10. __hash__() — не реализуется для dict

# Словари НЕИЗМЕНЯЕМЫ и не могут быть ключами других словарей
my_dict = {"a": 1}

# Это вызовет ошибку:
# dict_of_dicts = {my_dict: "value"}  # TypeError: unhashable type: dict

# Используем frozendict или кортеж:
dict_as_tuple = ((a, 1),)
dict_of_dicts = {dict_as_tuple: "value"}  # OK
print(dict_of_dicts)  # {((a, 1),): value}

Практические примеры с служебными методами

Пример 1: Словарь с логированием

class LogDict(dict):
    """Словарь, логирующий все операции"""
    
    def __setitem__(self, key, value):
        print(f"SET: {key} = {value}")
        super().__setitem__(key, value)
    
    def __getitem__(self, key):
        print(f"GET: {key}")
        return super().__getitem__(key)
    
    def __delitem__(self, key):
        print(f"DEL: {key}")
        super().__delitem__(key)

ld = LogDict()
ld["name"] = "Bob"  # Выведет: SET: name = Bob
print(ld["name"])   # Выведет: GET: name, затем Bob

Пример 2: Словарь по умолчанию

class DefaultDict(dict):
    """Словарь с значением по умолчанию"""
    
    def __init__(self, default_value, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.default_value = default_value
    
    def __getitem__(self, key):
        try:
            return super().__getitem__(key)
        except KeyError:
            return self.default_value

dd = DefaultDict("N/A", {"name": "Alice"})
print(dd["name"])    # Alice
print(dd["age"])     # N/A (не вызывает исключение)

Пример 3: Атомарные операции

class AtomicDict(dict):
    """Словарь с защитой от одновременного доступа"""
    
    def __setitem__(self, key, value):
        # Здесь можно добавить lock для потокобезопасности
        print(f"Атомарная запись: {key}")
        super().__setitem__(key, value)

Различие между методами

МетодВызываетсяПример
__getitem__dict[key]d["a"]
get()явноd.get("a")
__setitem__dict[key] = valued["a"] = 1
__delitem__del dict[key]del d["a"]
__len__len(dict)len(d)
__contains__key in dict"a" in d
__iter__for key in dictfor k in d

Сужебные методы — мощный инструмент для создания специализированных типов словарей с кастомным поведением, часто используемых в датасайенс приложениях для валидации данных и логирования.

Что такое служебный метод dict? | PrepBro