← Назад к вопросам
Какие методы нужно переопределить, чтобы объект себя вел как словарь?
2.2 Middle🔥 141 комментариев
#Python Core
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Методы для создания словаря-подобного объекта
В Python существует протокол для объектов, которые ведут себя как словари. Это называется Mapping Protocol. Расскажу о всех необходимых методах и примерах использования.
1. Основные методы: getitem, setitem, delitem
class SimpleDict:
def __init__(self):
self._data = {}
def __getitem__(self, key):
"""obj[key] - получение значения"""
return self._data[key]
def __setitem__(self, key, value):
"""obj[key] = value - установка значения"""
self._data[key] = value
def __delitem__(self, key):
"""del obj[key] - удаление значения"""
del self._data[key]
obj = SimpleDict()
obj['name'] = 'Alice' # __setitem__
print(obj['name']) # __getitem__: Alice
del obj['name'] # __delitem__
2. len и contains
class DictLike:
def __init__(self):
self._data = {}
def __getitem__(self, key):
return self._data[key]
def __setitem__(self, key, value):
self._data[key] = value
def __delitem__(self, key):
del self._data[key]
def __len__(self):
"""len(obj) - количество элементов"""
return len(self._data)
def __contains__(self, key):
"""key in obj - проверка наличия ключа"""
return key in self._data
obj = DictLike()
obj['a'] = 1
obj['b'] = 2
print(len(obj)) # 2
print('a' in obj) # True
print('c' in obj) # False
3. iter для итерирования по ключам
class IterableDict:
def __init__(self):
self._data = {}
def __getitem__(self, key):
return self._data[key]
def __setitem__(self, key, value):
self._data[key] = value
def __len__(self):
return len(self._data)
def __iter__(self):
"""Итерирование по ключам"""
return iter(self._data)
obj = IterableDict()
obj['x'] = 10
obj['y'] = 20
for key in obj: # Использует __iter__
print(f"{key}: {obj[key]}")
# x: 10
# y: 20
4. .keys(), .values(), .items()
from collections.abc import MutableMapping
class FullDict(MutableMapping):
"""Наследуем от MutableMapping для автоматических методов"""
def __init__(self):
self._data = {}
def __getitem__(self, key):
return self._data[key]
def __setitem__(self, key, value):
self._data[key] = value
def __delitem__(self, key):
del self._data[key]
def __len__(self):
return len(self._data)
def __iter__(self):
return iter(self._data)
obj = FullDict()
obj['a'] = 1
obj['b'] = 2
print(list(obj.keys())) # ['a', 'b']
print(list(obj.values())) # [1, 2]
print(list(obj.items())) # [('a', 1), ('b', 2)]
5. .get(), .pop(), .update() через MutableMapping
from collections.abc import MutableMapping
class SmartDict(MutableMapping):
def __init__(self, **kwargs):
self._data = kwargs
def __getitem__(self, key):
return self._data[key]
def __setitem__(self, key, value):
self._data[key] = value
def __delitem__(self, key):
del self._data[key]
def __len__(self):
return len(self._data)
def __iter__(self):
return iter(self._data)
obj = SmartDict(name='Alice', age=30)
print(obj.get('name')) # Alice
print(obj.get('email', 'N/A')) # N/A (дефолт)
obj.update({'email': 'alice@example.com'}) # Автоматический метод
print(obj._data) # {'name': 'Alice', 'age': 30, 'email': '...'}
value = obj.pop('age') # Удаляет и возвращает
print(value) # 30
6. Пример: OrderDict-подобный класс
from collections.abc import MutableMapping
from collections import OrderedDict
class OrderedDictLike(MutableMapping):
"""Словарь, сохраняющий порядок вставки"""
def __init__(self):
self._data = OrderedDict()
def __getitem__(self, key):
return self._data[key]
def __setitem__(self, key, value):
self._data[key] = value
def __delitem__(self, key):
del self._data[key]
def __len__(self):
return len(self._data)
def __iter__(self):
return iter(self._data)
def __repr__(self):
return f"OrderedDictLike({dict(self._data)})"
obj = OrderedDictLike()
obj['z'] = 1
obj['a'] = 2
obj['m'] = 3
print(list(obj.keys())) # ['z', 'a', 'm'] - порядок сохранён
7. Расширенная версия с валидацией
from collections.abc import MutableMapping
class ValidatedDict(MutableMapping):
"""Словарь с валидацией типов"""
def __init__(self, **schema):
self._data = {}
self.schema = schema # {'name': str, 'age': int}
def __getitem__(self, key):
return self._data[key]
def __setitem__(self, key, value):
if key in self.schema:
expected_type = self.schema[key]
if not isinstance(value, expected_type):
raise TypeError(f"{key} must be {expected_type}")
self._data[key] = value
def __delitem__(self, key):
del self._data[key]
def __len__(self):
return len(self._data)
def __iter__(self):
return iter(self._data)
config = ValidatedDict(name=str, port=int, debug=bool)
config['name'] = 'myapp' # OK
config['port'] = 8080 # OK
# config['port'] = 'abc' # TypeError: port must be <class 'int'>
8. Case-insensitive Dictionary
from collections.abc import MutableMapping
class CaseInsensitiveDict(MutableMapping):
"""Словарь, нечувствительный к регистру ключей"""
def __init__(self):
self._data = {}
def __getitem__(self, key):
return self._data[key.lower()]
def __setitem__(self, key, value):
self._data[key.lower()] = value
def __delitem__(self, key):
del self._data[key.lower()]
def __len__(self):
return len(self._data)
def __iter__(self):
return iter(self._data)
obj = CaseInsensitiveDict()
obj['Name'] = 'Alice'
print(obj['name']) # Alice
print(obj['NAME']) # Alice
9. Nested Dictionary (вложенный доступ)
from collections.abc import MutableMapping
class NestedDict(MutableMapping):
"""Словарь с вложенным доступом через точку"""
def __init__(self, data=None):
self._data = data or {}
def __getitem__(self, key):
value = self._data[key]
if isinstance(value, dict):
return NestedDict(value)
return value
def __setitem__(self, key, value):
self._data[key] = value
def __delitem__(self, key):
del self._data[key]
def __len__(self):
return len(self._data)
def __iter__(self):
return iter(self._data)
def __getattr__(self, key):
if key.startswith('_'):
return super().__getattribute__(key)
try:
return self[key]
except KeyError:
raise AttributeError(f"No attribute {key}")
data = {'user': {'name': 'Alice', 'age': 30}}
obj = NestedDict(data)
print(obj['user']['name']) # Alice
print(obj.user.name) # Alice
10. Сравнение подходов
| Подход | Сложность | Преимущества | Когда использовать |
|---|---|---|---|
| Базовые методы | Низкая | Полный контроль | Простые случаи |
| MutableMapping | Средняя | Готовые методы | Большинство случаев |
| Расширенные | Высокая | Кастомное поведение | Специальные требования |
Минимальный набор методов
class MinimalDict:
"""Минимум для словаря-подобного поведения"""
def __init__(self):
self._data = {}
def __getitem__(self, key):
return self._data[key]
def __setitem__(self, key, value):
self._data[key] = value
def __delitem__(self, key):
del self._data[key]
def __len__(self):
return len(self._data)
def __iter__(self):
return iter(self._data)
def __contains__(self, key):
return key in self._data
Лучшие практики
- Используй collections.abc.MutableMapping если нужна полная функциональность
- Переопредели только необходимые методы — остальные унаследуются
- Добавляй валидацию в setitem для защиты данных
- Реализуй repr для красивого вывода
- Документируй поведение отличное от обычного dict
Профессиональные примеры использования: ORM объекты, конфиги, кеши, API клиенты.