Добавление collections.defaultdict
в Python 2.5 значительно снижается необходимость dict
«S setdefault
метода. Этот вопрос для нашего коллективного образования:
- Для чего
setdefault
все еще полезно сегодня Python 2.6 / 2.7? - Какие популярные варианты использования
setdefault
были замененыcollections.defaultdict
?
python
dictionary
setdefault
Эли Бендерский
источник
источник
Ответы:
Можно сказать, что
defaultdict
это полезно для настроек по умолчанию перед заполнением dict иsetdefault
полезно для установки настроек по умолчанию во время или после заполнения dict .Вероятно, наиболее распространенный вариант использования: группировка элементов (в несортированных данных, другое использование
itertools.groupby
)Иногда вы хотите убедиться, что определенные ключи существуют после создания dict.
defaultdict
не работает в этом случае, потому что он создает ключи только при явном доступе. Думаю, вы используете что-то HTTP-иш со многими заголовками - некоторые являются необязательными, но вы хотите по умолчанию для них:источник
defaultdict
. Можете ли вы привести пример того, что вы имеете в виду в первом абзаце?setdefault
.defaultdict
с другой стороны, не сработало бы, если бы не всеdefaultvalues
были равны (то есть некоторые есть,0
а некоторые есть[]
).headers = dict(optional_headers)
. Для случая, когда значения по умолчанию не все равны. И конечный результат такой же, как если бы вы сначала получили заголовки HTTP, а затем установили значения по умолчанию для тех, кого вы не получили. И это очень удобно, если у вас уже естьoptional_headers
. Попробуйте мой двухэтапный код и сравните его с вашим, и вы поймете, что я имею в виду.new.setdefault(key, []).append(value)
defaultdict
что даже лучше, чемsetdefault
(так, где сейчас сценарий использования?). Кроме того,ChainMap
лучше бы справиться сhttp
примером, ИМО.Я обычно использую
setdefault
для ключевых слов аргументы, такие как в этой функции:Он отлично подходит для настройки аргументов в оболочках вокруг функций, которые принимают аргументы ключевых слов.
источник
defaultdict
замечательно, когда значение по умолчанию статично, как новый список, но не так сильно, если оно динамическое.Например, мне нужен словарь для сопоставления строк с уникальными целочисленными значениями.
defaultdict(int)
всегда будет использовать 0 для значения по умолчанию. Точно так же,defaultdict(intGen())
всегда выдает 1.Вместо этого я использовал обычный dict:
Обратите внимание, что этого
dict.get(key, nextID())
недостаточно, потому что мне нужно иметь возможность ссылаться на эти значения позже.intGen
это крошечный класс, который я создаю, который автоматически увеличивает int и возвращает его значение:Если у кого-то есть способ сделать это,
defaultdict
я бы с удовольствием это увидел.источник
intGen
наitertools.count().next
.nextID()
Значение будет увеличиваться при каждомmyDict.setdefault()
вызове, даже если возвращаемое значение не используется какstrID
. Это кажется расточительным и иллюстрирует одну из вещей, которые мне не нравятсяsetdefault()
в целом, а именно то, что он всегда оценивает свойdefault
аргумент независимо от того, используется ли он на самом деле.defaultdict
:myDict = defaultdict(lambda: nextID())
. ПозжеstrID = myDict[myStr]
в цикле.myDict = defaultdict(nextID)
?Я использую,
setdefault()
когда я хочу значение по умолчанию вOrderedDict
. Существует не стандартный набор Python , который делает как, но есть способы , чтобы реализовать такую коллекцию.источник
Поскольку большинство ответов указывают
setdefault
илиdefaultdict
позволят вам установить значение по умолчанию, когда ключ не существует. Тем не менее, я хотел бы указать на небольшое предостережение в отношении случаев использованияsetdefault
. Когда интерпретатор Python выполняется,setdefault
он всегда оценивает второй аргумент функции, даже если ключ существует в словаре. Например:Как видите,
print
также был выполнен, хотя 2 уже существовало в словаре. Это становится особенно важным, если вы планируете использовать,setdefault
например, для оптимизации, какmemoization
. Если вы добавите рекурсивный вызов функции в качестве второго аргументаsetdefault
, вы не получите никакой производительности, так как Python всегда будет вызывать функцию рекурсивно.Поскольку упоминание было упомянуто, лучшей альтернативой является использование декоратора functools.lru_cache, если вы планируете усовершенствовать функцию с помощью памятки. lru_cache лучше обрабатывает требования кеширования для рекурсивной функции.
источник
Как сказал Мухаммед, есть ситуации, в которых вы только иногда хотите установить значение по умолчанию. Отличным примером этого является структура данных, которая сначала заполняется, а затем запрашивается.
Рассмотрим три. При добавлении слова, если подузел необходим, но отсутствует, он должен быть создан для расширения дерева. При запросе наличия слова отсутствующий подузел указывает, что слово отсутствует и его не следует создавать.
Defaultdict не может этого сделать. Вместо этого следует использовать обычный dict с методами get и setdefault.
источник
Теоретически,
setdefault
все равно было бы удобно, если бы вы иногда хотите установить значение по умолчанию, а иногда нет. В реальной жизни я не встречал такого случая использования.Однако из стандартной библиотеки возникает интересный пример использования (Python 2.6, _threadinglocal.py):
Я бы сказал, что использование
__dict__.setdefault
это довольно полезный случай.Изменить : Как это бывает, это единственный пример в стандартной библиотеке, и это в комментарии. Так что, может быть, этого недостаточно, чтобы оправдать существование
setdefault
. Тем не менее, вот объяснение:Объекты хранят свои атрибуты в
__dict__
атрибуте. Как это бывает,__dict__
атрибут доступен для записи в любое время после создания объекта. Это также словарь, а неdefaultdict
. Для объектов в общем случае не имеет смысла иметь__dict__
это,defaultdict
потому что каждый объект имеет все юридические идентификаторы в качестве атрибутов. Поэтому я не могу предвидеть каких-либо изменений в объектах Python, от которых можно избавиться__dict__.setdefault
, за исключением полного удаления, если это будет сочтено бесполезным.источник
__dict__
реализация, аdict
неdefaultdict
.setdefault
остаться в Python, но любопытно, что теперь это почти бесполезно.setdefault
ясно указывает, что вы присваиваете dict ключ, который может существовать или не существовать, и, если он не существует, вы хотите, чтобы он был создан со значением по умолчанию: напримерd.setdefault(key,[]).append(value)
. В другом месте в программе вы делаете,alist=d[k]
где вычисляется k, и вы хотите, чтобы исключение было выброшено, если k не в d (что может потребоваться по умолчанию,assert k in d
или дажеif not ( k in d): raise KeyError
Один из недостатков
defaultdict
overdict
(dict.setdefault
) состоит в том, чтоdefaultdict
объект создает новый элемент КАЖДОЙ ВРЕМЯ, если задан несуществующий ключ (например, с==
,print
). Кроме того,defaultdict
класс, как правило, гораздо реже, чемdict
класс, его сложнее сериализовать в IME.PS IMO функции | методы, не предназначенные для изменения объекта, не должны изменять объект.
источник
defaultdict(lambda l=[]: l)
вместо этого.Вот несколько примеров setdefault, чтобы показать его полезность:
источник
Я переписал принятый ответ и предоставил его новичкам.
Кроме того, я классифицировал методы как ссылки:
источник
Я часто использую setdefault, когда получаю это, устанавливая значение по умолчанию (!!!) в словаре; довольно часто словарь os.environ:
Менее кратко, это выглядит так:
Стоит отметить, что вы также можете использовать результирующую переменную:
Но это менее необходимо, чем это было до существования дефолтов.
источник
Другой вариант использования, о котором я не думаю, был упомянут выше. Иногда вы сохраняете кеш-объект объектов по их идентификатору, где основной экземпляр находится в кеше, и вы хотите установить кеш при отсутствии.
Это полезно, когда вы всегда хотите сохранить один экземпляр для отдельного идентификатора, независимо от того, как вы получаете объект каждый раз. Например, когда атрибуты объекта обновляются в памяти и сохранение в хранилище откладывается.
источник
Один очень важный пример использования, на который я наткнулся:
dict.setdefault()
отлично подходит для многопоточного кода, когда вам нужен только один канонический объект (в отличие от нескольких объектов, которые оказываются равными).Например,
(Int)Flag
Enum в Python 3.6.0 содержит ошибку : если несколько потоков конкурируют за составной(Int)Flag
элемент, может оказаться более одного:Решение состоит в том, чтобы использовать
setdefault()
в качестве последнего шага сохранения вычисляемого составного элемента - если другой уже был сохранен, то он используется вместо нового, гарантируя уникальные члены Enum.источник
[Править] Очень неправильно!Setdefault всегда запускает long_computation, а Python стремится к этому.
Расширяя ответ Таттла. Для меня лучшим вариантом использования является механизм кэширования. Вместо того:
который потребляет 3 строки и 2 или 3 поиска,
я бы с радостью написал:источник
long_computation(x)
называется только еслиx not in memo
. Тогда как во второмlong_computation(x)
всегда называется. Только присвоение является условным, эквивалентный кодsetdefault
будет выглядеть так:v = long_computation(x)
/if x not in memo:
/memo[x] = v
.Мне нравится ответ, приведенный здесь:
http://stupidpythonideas.blogspot.com/2013/08/defaultdict-vs-setdefault.html
Короче говоря, решение (в приложениях, не критичных к производительности) должно приниматься исходя из того, как вы хотите обрабатывать поиск пустых ключей в нисходящем направлении ( а именно, по
KeyError
сравнению со значением по умолчанию).источник
Другой вариант использования
setdefault()
- это когда вы не хотите перезаписывать значение уже установленного ключа.defaultdict
перезаписывает, покаsetdefault()
нет. Для вложенных словарей чаще всего требуется установить значение по умолчанию только в том случае, если ключ еще не установлен, поскольку вы не хотите удалять текущий вложенный словарь. Это когда вы используетеsetdefault()
.Пример с
defaultdict
:setdefault
не перезаписывать:источник