Как стать автором
Поиск
Написать публикацию
Обновить

Комментарии 8

Формально нужна хэшируемость и сравнимость объектов, но по факту проще запомнить не изменяемость. Проблема с изменяемыми объектами в том, что у них при изменении меняется либо хэш, либо значение и вы уже не сможете нормально найти ключ в словаре, который ранее был задан таким объектом. Они могут и не измениться, но гарантии нет. Поэтому, от греха подальше, изменяемым объектам стараются просто не делать доступной функцию хэширования, чтобы не было возможности их использовать в качестве ключа для словаря и собирать грабли после этого.

Ну а когда вы объявляете свой класс, а не пользуетесь готовым, питон за вас заранее не знает, что у вас там будет с изменяемостью, поэтому вы сами должны проследить за тем, будет ли у вашего класса функция хэширования и если да, то вы должны сделать её адекватной и сообразной функции сравнения.

все верно, для упрощения говорим, что ключи - неизменяемые типы данных, вряд ли ключами словаря будут объекты функций и экземпляры классов, но нужно упор делать на хешируемость

Вы относите слово "неизменяемый" к содержимому структуры данных, но применительно к ключам ассоциативного массива (в Python - "словаря") смотреть надо не на неизменяемость содержимого, а на неизменяемость того, что хэшируется и/или сравнивается операциями == и !=.

В случае объектов хэшируется/сравнивается не содержимое объектов, а никак не изменяемые указатели (адрес в памяти, id в таблице объектов и т.п.) этих объектов. Независимо от того, как меняются значения полей объекта, указатель и хэш, полученный из этого указателя, остаются неизменными. Аналогично с функциями.

"зачастую на интернет-ресурсах про ключи говорят как про объекты неизменяемых типов данных,"

Не знаю где так говорят, если читать книги по Rust и С++ там сказано если ты можешь захешировать свой тип - вперёд

здесь в контексте Python

dct = {obj_1: 1, obj_2: 2}

Хм, интересная конструкция: мы присваивает каждому объекту значение, например, рейтинг, при этом не внутри объекта, т.е. ни объект, ни класс об этом "не знают". Где бы это могло пригодиться? [Дай 10 вариантов] - строка, отделяющая теперешнее время от времени ещё несколько лет назад...

Ответ deepseek, который ещё несколько лет назад был бы немыслимо ждать от машины:

Отличный вопрос! Хранение внешних атрибутов объектов в словаре — мощный паттерн, особенно когда нельзя или нежелательно модифицировать сами классы объектов. Вот 10 практических применений:

  1. Кэширование результатов вычислений:

    • cache = {obj: expensive_calculation(obj) for obj in objects}

    • Пригодится: Для тяжёлых функций (рендеринг, сложные математические операции). Избегаем повторных вычислений для одного объекта.

  2. Временные состояния/флаги:

    • selected_objects = {obj_1: True, obj_2: False}

    • Пригодится: UI (выделение элементов), обработка событий ("уже обработан"), временные отметки в алгоритмах (обход графа - visited[node] = True).

  3. Связывание метаданных:

    • object_metadata = {obj: {"last_accessed": timestamp, "owner": user_id}}

    • Пригодится: Системы кеширования (время доступа), аудит (кто последний менял), контекстная информация для обработки.

  4. Подсчёт частоты / Агрегация:

    • word_count = {}; for word in words: word_count[word] = word_count.get(word, 0) + 1

    • Пригодится: Анализ текста (частотность слов), подсчёт событий (сколько раз пользователь выполнил действие), поиск дубликатов.

  5. Сопоставление объектов с внешними ресурсами:

    • texture_mapping = {game_object: texture_id}

    • Пригодится: Графика (связь модели с текстурой), базы данных (связь объекта ORM с ID записи), сетевые соединения (связь пользователя с сокетом).

  6. Приоритизация / Очереди:

    • priority_queue = []; heapq.heappush(priority_queue, (priority_dict[task], task))

    • Пригодится: Планировщики задач (приоритет задачи не свойство самой задачи, а определяется контекстом), алгоритмы поиска пути (A* - f_score[node] = ...).

  7. Вес рёбер / Сила связей (Графы):

    • graph[from_node] = {to_node: weight, ...}

    • Пригодится: Представление взвешенных графов (социальные сети - сила связи, карты - расстояние/время проезда). Вес - атрибут связи, а не узла.

  8. Внешняя конфигурация / Настройки:

    • object_settings = {widget: {"color": "red", "size": 10}}

    • Пригодится: GUI (стилизация элементов, которые не хранят стиль внутри), управление поведением плагинов. Настройки задаются извне.

  9. Группировка / Классификация:

    • groups = {"admin": [user1, user2], "user": [user3]}

    • Пригодится: Системы прав доступа (группы пользователей), категоризация элементов (товары в категориях). Группа - внешний контейнер.

  10. Хранение сессионных данных:

    • session_store = {session_id: {"user": user_obj, "cart": cart_items}}

    • Пригодится: Веб-приложения. Данные сессии (корзина покупок, состояние) привязаны к идентификатору сессии, а не к объекту пользователя напрямую (особенно если пользователь не залогинен).

Ключевые преимущества такого подхода:

  • Неинвазивность: Не нужно изменять исходные классы объектов.

  • Гибкость: Легко добавлять, изменять и удалять атрибуты для объектов динамически.

  • Разделение ответственности: Данные, специфичные для контекста использования, хранятся отдельно от базовых данных объекта.

  • Эффективность: Быстрый (O(1) в среднем) доступ к данным по ключу-объекту.

  • Работа с "чужими" объектами: Можно прикреплять данные к объектам из библиотек, код которых вы не контролируете.

Важные замечания:

  • Хешируемость: Ключи словаря (ваши объекты) должны быть хешируемыми (в Python обычно реализуют hash и eq).

  • Сравнение по ссылке: По умолчанию в Python объекты сравниваются по идентификатору (адресу в памяти). Это часто ожидаемо в таких сценариях.

  • Жизненный цикл: Словарь хранит сильные ссылки на объекты-ключи. Это может препятствовать сборке мусора, если объект больше нигде не используется, но остался в словаре. Для временных данных используйте weakref.WeakKeyDictionary.

Этот паттерн — отличный инструмент для случаев, когда данные контекстно-зависимы или временны, и их не стоит "зашивать" в саму сущность объекта.

Хз откуда здесь "чудеса" и "открытия". Это буквально база работы со словарями о которой написано в любой нормальной книге по питону. Или любом нормальном курсе. Да и статей где бы все детально разжёвывалось (real python тот же) предостаточно...

но на эти нюансы не все обращают внимание, не лишним будет еще раз повторить

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации