HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-02-26
1 <p>Представьте ситуацию: вам нужно хранить в словаре в качестве значений списки или любые другие изменяемые данные. У вас есть ключ и элемент для добавления в список-значение, но сам ключ в словаре может быть не представлен. В таком случае придется писать подобный код:</p>
1 <p>Представьте ситуацию: вам нужно хранить в словаре в качестве значений списки или любые другие изменяемые данные. У вас есть ключ и элемент для добавления в список-значение, но сам ключ в словаре может быть не представлен. В таком случае придется писать подобный код:</p>
2 <p>Подобная ситуация встречается не так уж и редко. Это понимали и авторы стандартной библиотеки Python и дали словарю метод setdefault. Именно этот метод мы рассмотрим подробнее в этом уроке.</p>
2 <p>Подобная ситуация встречается не так уж и редко. Это понимали и авторы стандартной библиотеки Python и дали словарю метод setdefault. Именно этот метод мы рассмотрим подробнее в этом уроке.</p>
3 <h2>Инициализация новых значений</h2>
3 <h2>Инициализация новых значений</h2>
4 <p>Попробуем переписать код выше с помощью метода setdefault:</p>
4 <p>Попробуем переписать код выше с помощью метода setdefault:</p>
5 <p>Метод setdefault принимает ключ и значение по умолчанию, а затем возвращает ссылку на значение в словаре, связанное с указанным ключом. Если ключ в словаре отсутствует, то метод помещает по ключу то самое значение по умолчанию и возвращает ссылку на него. В примере выше значением по умолчанию выступает пустой список [].</p>
5 <p>Метод setdefault принимает ключ и значение по умолчанию, а затем возвращает ссылку на значение в словаре, связанное с указанным ключом. Если ключ в словаре отсутствует, то метод помещает по ключу то самое значение по умолчанию и возвращает ссылку на него. В примере выше значением по умолчанию выступает пустой список [].</p>
6 <h2>Тип defaultdict</h2>
6 <h2>Тип defaultdict</h2>
7 <p>В стандартной поставке Python присутствует модуль collections, который предоставляет тип defaultdict. Во всех отношениях defaultdict - это обычный словарь. При этом у него есть одно уникальное свойство: там, где обычный словарь ругается на отсутствие ключа, defaultdict сам возвращает значение по умолчанию. Давайте рассмотрим пример:</p>
7 <p>В стандартной поставке Python присутствует модуль collections, который предоставляет тип defaultdict. Во всех отношениях defaultdict - это обычный словарь. При этом у него есть одно уникальное свойство: там, где обычный словарь ругается на отсутствие ключа, defaultdict сам возвращает значение по умолчанию. Давайте рассмотрим пример:</p>
8 <p>При создании словаря мы указали в качестве аргумента функцию int. Если эту функцию вызвать без аргументов, то она вернет 0. Именно этот вызов внутри словаря d и происходит всякий раз, когда нужно получить значение для несуществующего ключа.</p>
8 <p>При создании словаря мы указали в качестве аргумента функцию int. Если эту функцию вызвать без аргументов, то она вернет 0. Именно этот вызов внутри словаря d и происходит всякий раз, когда нужно получить значение для несуществующего ключа.</p>
9 <p>В примере выше d["a"] += 5 дает 5, потому что этот код работает так:</p>
9 <p>В примере выше d["a"] += 5 дает 5, потому что этот код работает так:</p>
10 <ul><li>Сначала для ключа "a" создается начальное значение - делается вызов int() и получается 0</li>
10 <ul><li>Сначала для ключа "a" создается начальное значение - делается вызов int() и получается 0</li>
11 <li>Уже потом к нему прибавляется 5</li>
11 <li>Уже потом к нему прибавляется 5</li>
12 </ul><p>В строчке d["b"] = d["c"] + 10 создаются значения для ключей "b" и "c". Затем уже по ключу "b" записывается сумма 0 + 10.</p>
12 </ul><p>В строчке d["b"] = d["c"] + 10 создаются значения для ключей "b" и "c". Затем уже по ключу "b" записывается сумма 0 + 10.</p>
13 <p>Вот еще один пример - на этот раз с самодельной функцией-инициализатором:</p>
13 <p>Вот еще один пример - на этот раз с самодельной функцией-инициализатором:</p>
14 <p>Попробуем отбросить немного непонятное упоминание функции-инициализатора. Так станет видно, что теперь строки 'foo' записаны по всем ключам, по которым мы обращались к содержимому словаря.</p>
14 <p>Попробуем отбросить немного непонятное упоминание функции-инициализатора. Так станет видно, что теперь строки 'foo' записаны по всем ключам, по которым мы обращались к содержимому словаря.</p>
15 <h2>Отличия defaultdict от обычного словаря с setdefault</h2>
15 <h2>Отличия defaultdict от обычного словаря с setdefault</h2>
16 <p>Пока не совсем понятно, зачем иметь оба способа, если они настолько похожи. Но давайте сравним эти две строки:</p>
16 <p>Пока не совсем понятно, зачем иметь оба способа, если они настолько похожи. Но давайте сравним эти две строки:</p>
17 <p>Строки очень похожи, но есть одно различие:</p>
17 <p>Строки очень похожи, но есть одно различие:</p>
18 <ul><li>В первом случае объект пустого списка будет создаваться каждый раз</li>
18 <ul><li>В первом случае объект пустого списка будет создаваться каждый раз</li>
19 <li>Во втором случае новый список создается только тогда, когда ключ не будет найден</li>
19 <li>Во втором случае новый список создается только тогда, когда ключ не будет найден</li>
20 </ul><p>Значения аргументов всегда вычисляются до того, как будет вызвана функция. Поэтому здесь в случае с setdefault(key, []) затратами на создание пустого списка можно пренебречь. Если вдруг затраты на создание значения по умолчанию окажутся велики, вариант с defaultdict окажется гораздо предпочтительнее.</p>
20 </ul><p>Значения аргументов всегда вычисляются до того, как будет вызвана функция. Поэтому здесь в случае с setdefault(key, []) затратами на создание пустого списка можно пренебречь. Если вдруг затраты на создание значения по умолчанию окажутся велики, вариант с defaultdict окажется гораздо предпочтительнее.</p>
21 <p>Зачем вообще использовать setdefault? Например, он помогает инициализировать разные значения по разным ключам. Значение по умолчанию передается каждый раз, поэтому мы можем хранить по разным ключам даже разные типы данных.</p>
21 <p>Зачем вообще использовать setdefault? Например, он помогает инициализировать разные значения по разным ключам. Значение по умолчанию передается каждый раз, поэтому мы можем хранить по разным ключам даже разные типы данных.</p>
22 <p>С defaultdict у нас нет контроля над тем, какие значения по каким ключам класть. Функция-инициализатор вызывается каждый раз одна и та же - ключ в нее не передается.</p>
22 <p>С defaultdict у нас нет контроля над тем, какие значения по каким ключам класть. Функция-инициализатор вызывается каждый раз одна и та же - ключ в нее не передается.</p>
23 <p>Наконец, всегда остаются редкие случаи, когда и defaultdict не подходит. Например, если нужно инициализировать значения по-разному, но не подходит и setdefault. Новые значения неизменяемы, их не получится изменить по возвращаемой ссылке. Рассмотрим пример такого случая вместе с решением задачи ненахождения ключа:</p>
23 <p>Наконец, всегда остаются редкие случаи, когда и defaultdict не подходит. Например, если нужно инициализировать значения по-разному, но не подходит и setdefault. Новые значения неизменяемы, их не получится изменить по возвращаемой ссылке. Рассмотрим пример такого случая вместе с решением задачи ненахождения ключа:</p>
24 <p>Обратите внимание, что в этом коде присутствуют лишние хождения по одному и тому же ключу. При этом сам код читается неплохо - в данной ситуации его можно назвать оптимальным.</p>
24 <p>Обратите внимание, что в этом коде присутствуют лишние хождения по одному и тому же ключу. При этом сам код читается неплохо - в данной ситуации его можно назвать оптимальным.</p>