Есть ли причины не использовать упорядоченный словарь?
Я имею в виду OrderedDict С collections модуль.
если он имеет дополнительную функциональность упорядочивания, которая, как я понимаю, часто не нужна, но даже так, есть ли какие-либо недостатки? Это медленнее? Отсутствует ли какая-либо функциональность? Я не видел никаких недостающих методов.
короче, Почему не стоит Я всегда использую это вместо обычного словаря?
3 ответов:
OrderedDictявляется наследникомdict, и требуется больше памяти, чтобы отслеживать порядок, в котором ключи. Это не тривиально. Реализация добавляет второйdictпод обложками, и двусвязный список всех ключей (это та часть, которая помнит порядок), и куча прокси weakref. Это не много медленнее, но по крайней мере удваивает память с помощью простогоdict.но если это уместно, используйте его! Вот почему он там : -)
как это работает
базовый dict-это просто обычный dict, отображающий ключи к значениям-он вообще не "упорядочен". Когда
<key, value>пара добавляется,keyдобавляется в список. Список-это та часть, которая запоминает порядок.но если бы это был список Python, удаление ключ бы взял
O(n)время дважды:O(n)времени, чтобы найти ключ в списке, иO(n)времени, чтобы удалить ключ из список.так что это двусвязный список вместо этого. Это делает удаление ключевой константы (
O(1)) времени. Но нам все равно нужно найти узел двусвязного списка, принадлежащий ключу. Чтобы сделать эту операциюO(1)время тоже, второй-скрытый-дикт отображает ключи к узлам в двусвязном списке.так что добавление нового
<key, value>pair требует добавления пары в базовый dict, создания нового узла двусвязного списка для хранения ключа, добавления этого нового узла к двусвязный список и сопоставление ключа с этим новым узлом в скрытом Дикте. Чуть более чем в два раза больше работы, но все жеO(1)(ожидаемый случай) время в целом.аналогично, удаление ключа, который присутствует также немного более чем в два раза больше работы, но
O(1)ожидаемое время в целом: используйте скрытый дикт, чтобы найти узел двусвязного списка ключа, удалить этот узел из списка и удалить ключ из обоих диктов.Etc. Это довольно эффективно.
многопоточность
Если ваш словарь вызывается из нескольких потоков без блокировки, особенно в качестве точки синхронизации.
операции vanilla dict являются атомарными, а любой тип extended в Python-нет.
на самом деле, я даже не уверен, что OrderedDict является потокобезопасным (без замка), хотя Я не исключаю, что оно было очень тщательно закодированы и определению удовлетворяет и реентерабельности.
меньшее дьяволы
использование памяти, если вы создаете тонны этих словарей
использование ЦП, если весь ваш код делает это munge эти словари
почему я не должен всегда использовать это вместо обычного словаря
В Python 2.7, нормальный
OrderedDictиспользование создаст опорные циклы. Так что любое использованиеOrderedDictтребуется включить сборщик мусора, чтобы освободить память. Да, сборщик мусора включен по умолчанию в cPython, но отключает его имеет свои использует.например, с cPython 2.7.14
from __future__ import print_function import collections import gc if __name__ == '__main__': d = collections.OrderedDict([('key', 'val')]) gc.collect() del d gc.set_debug(gc.DEBUG_LEAK) gc.collect() for i, obj in enumerate(gc.garbage): print(i, obj)выходы
gc: collectable <list 00000000033E7908> gc: collectable <list 000000000331EC88> 0 [[[...], [...], 'key'], [[...], [...], 'key'], None] 1 [[[...], [...], None], [[...], [...], None], 'key']даже если вы просто создаете пустой
OrderedDict(d = collections.OrderedDict()) и ничего не добавляйте к нему, или вы явно пытаетесь очистить его, вызвавclearметод (d.clear()доdel d), вы все равно получите один список самореференции:gc: collectable <list 0000000003ABBA08> 0 [[...], [...], None]это, кажется, было так с тех пор этот коммит удалены
__del__метод для предотвращения потенциала дляOrderedDictпричиной безнадежной циклы, которые, возможно, хуже. Как отмечено в журнале изменений для этого commit:выпуск #9825: удалено _ _ del__ из определения коллекций.OrderedDict. Это предотвращает создание пользователем самореферентных упорядоченных словарей из становится постоянно не собираемым мусором GC. Недостатком является то, что удаление _ _ del_ _ означает, что внутренний двусвязный список должен ждать Коллекция GC, а не освобождение памяти сразу же, когда refcnt капли обнулить.
обратите внимание, что в Python 3, то исправить для одной и той же проблемы было сделано по-разному и использует прокси weakref, чтобы избежать циклов:
проблема №9825: использование _ _ del__ в определении коллекций.OrderedDict сделал это возможно для пользователя, чтобы создать автореферентное упорядоченные словари которые становятся постоянно не собираемым мусором GC. Восстановил Py3. 1 подход использования прокси weakref так что ссылка циклы никогда не создаются во-первых.
Comments