Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Служебные методы 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] = value | d["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 dict | for k in d |
Сужебные методы — мощный инструмент для создания специализированных типов словарей с кастомным поведением, часто используемых в датасайенс приложениях для валидации данных и логирования.