Выставляя `defaultdict` как обычный` dict`

Я использую defaultdict(set) для заполнения внутреннего сопоставления в очень большой структуре данных. После его заполнения вся структура (включая отображение) подвергается клиенту. В этот момент я не хочу, чтобы кто-либо модифицировал отображение.

И никто не делает это намеренно. Но иногда код клиента может случайно ссылаться на элемент, который не существует. В этот момент нормальный словарь поднял бы KeyError , но поскольку отображение является defaultdict , оно просто создает новый элемент (пустой набор) на этом ключе. Это довольно сложно поймать, поскольку все происходит тихо. Но мне нужно, чтобы этого не произошло (семантика на самом деле не сломается, но отображение растет до огромного размера).

Что мне делать? Я вижу эти варианты:

  1. Найдите все экземпляры в текущем и будущем клиентском коде, где выполняется поиск словаря при сопоставлении, и конвертируйте его в mapping.get(k, {}) . Это просто ужасно.

  2. «Замораживание» defaultdict после полной инициализации структуры данных путем преобразования ее в dict . (Я знаю, что это действительно не заморожено, но я доверяю клиентскому коду, чтобы на самом деле не писать mapping[k] = v .) Inelegant и большой удар производительности.

  3. Оберните defaultdict в интерфейс dict . Какой элегантный способ сделать это? Боюсь, что удар производительности может быть огромным (этот поиск сильно используется в жестких циклах).

  4. Подкласс defaultdict и добавьте метод, который «отключает» все функции defaultdict , оставляя его вести себя так, как если бы он был обычным dict . Это вариант из 3 выше, но я не уверен, что это быстрее. И я не знаю, выполнимо ли это, не полагаясь на детали реализации.

  5. Используйте регулярный dict в структуре данных, переписывая весь код там, чтобы сначала проверить, находится ли элемент в словаре, и добавить его, если это не так. Нехорошо.

3 Solutions collect form web for “Выставляя `defaultdict` как обычный` dict`”

defaultdict docs говорят для default_factory :

Если атрибут default_factory равен None, это вызывает исключение KeyError с ключом в качестве аргумента.

Что делать, если вы просто установили default_factory defaultdict равным None ? Например,

 >>> d = defaultdict(int) >>> d['a'] += 1 >>> d defaultdict(<type 'int'>, {'a': 1}) >>> d.default_factory = None >>> d['b'] += 2 Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'b' >>> 

Не уверен, что это лучший подход, но, похоже, работает.

Вы можете создать класс, содержащий ссылку на ваш dict и запретить setitem ()

 from collections import Mapping class MyDict(Mapping): def __init__(self, d): self.d = d; def __getitem__(self, k): return self.d[k] def __iter__(self): return self.__iter__() def __setitem__(self, k, v): if k not in self.d.keys(): raise KeyError else: self.d[k] = v 

Когда вы закончите заполнять свой defaultdict, вы можете просто создать из него обычный dict:

 my_dict = dict(my_default_dict) 

Регулярный дикт, конечно, эффективно заморожен.

Если ваш dict по умолчанию является рекурсивным по умолчанию, см. Этот ответ, в котором используется рекурсивное решение.

  • Запуск нескольких версий uwsgi python
  • Перенаправление `sys.stdout` в файл или буфер
  • Будет ли setuptools работать с python 3.2.x
  • Запись с помощью встроенного модуля .csv Python
  • Вычисление энтропии Шеннона HTTP-заголовка с использованием Python. Как это сделать?
  • «Протоколы нельзя использовать с isinstance ()» - почему бы и нет?
  • Конфликты между унитатом и носом
  • Почему мои лямбды не работают?
  • Python - лучший язык программирования в мире.