# Как перебрать словарь в Python

Словари являются одной из наиболее важных и полезных структур данных в Python. Они могут помочь вам решить широкий спектр задач программирования. Из этой статьи вы узнаете, как итерировать словарь в Python.

**К концу этой статьи вы узнаете:**

- Что такое словари, а также некоторые их основные функции и детали реализации
- Как итерировать словарь в Python, используя основные инструменты, предлагаемые языком
- Какие реальные задачи вы можете выполнить, просматривая словарь в Python
- Как использовать некоторые более продвинутые методы и стратегии для перебора словаря в Python

Для получения дополнительной информации о словарях, вы можете обратиться к следующим ресурсам:

- [Dictionaries in Python](https://realpython.com/python-dicts)
- [Itertools in Python 3, By Example](https://realpython.com/python-itertools)
- The documentation for `<a aria-label=" (откроется в новой вкладке)" href="https://docs.python.org/3/library/functions.html#map" rel="noreferrer noopener" target="_blank">map()</a>` and `<a aria-label=" (откроется в новой вкладке)" href="https://docs.python.org/3/library/functions.html#filter" rel="noreferrer noopener" target="_blank">filter()</a>`

Готовы? Поехали!

## Несколько слов о словарях

Словари являются краеугольным камнем Python. Сам язык построен вокруг словарей. Модули, классы, объекты, globals(), locals(): все это словари. Словари были центральным элементом для Python с самого начала.

[Официальная документация Python](https://docs.python.org/3/index.html) определяет словарь следующим образом:

> Ассоциативный массив, где произвольные ключи отображаются на значения. Ключами могут быть любые объекты с методами \_\_hash\_\_() и \_\_eq\_\_(). ([Источник](https://docs.python.org/3/glossary.html#term-dictionary))

Есть несколько моментов, о которых следует помнить:

1. Словари сопоставляют ключи со значениями и сохраняют их в массиве или коллекции.
2. Ключи должны быть хэшируемого типа ([hashable](https://docs.python.org/3/glossary.html#term-hashable)), что означает, что в качестве ключа используют хэш значения ключа, который никогда не меняется в течение срока жизни ключа.

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

В отличие от последовательностей (**[sequences](https://docs.python.org/3/glossary.html#term-sequence)**), которые так же являются итерационными поддерживающими доступ к элементам с использованием целочисленных индексов, словари индексируются по ключам.

Ключи в словаре очень похожи на множества `<a aria-label=" (откроется в новой вкладке)" href="https://realpython.com/python-sets/" rel="noreferrer noopener" target="_blank">set</a>`, представляющие собой коллекцию уникальных объектов, которые можно хэшировать. Поскольку объекты должны быть хешируемыми, изменяемые ([mutable](https://docs.python.org/3/glossary.html#term-mutable)) объекты нельзя использовать в качестве ключей словаря.

С другой стороны, значения могут быть любого типа Python, независимо от того, являются они хэшируемыми или нет. Там нет буквально никаких ограничений.

В Python 3.6 и более поздних версиях ключи и значения словаря перебираются в том же порядке, в котором они были созданы. Однако это поведение может отличаться в разных версиях Python и зависит от истории вставок и удалений словаря.

В Python 2.7 словари являются неупорядоченными структурами. Порядок элементом словарей неизменяемый. Это означает, что порядок элементов является детерминированным и повторяемым. Давайте посмотрим на пример:

```python
>>> # Python 2.7
>>> a_dict = {'color': 'blue', 'fruit': 'apple', 'pet': 'dog'}
>>> a_dict
{'color': 'blue', 'pet': 'dog', 'fruit': 'apple'}
>>> a_dict
{'color': 'blue', 'pet': 'dog', 'fruit': 'apple'}
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%95%D1%81%D0%BB%D0%B8-%D0%B2%D1%8B-%D0%BF%D0%BE%D0%BA%D0%B8%D0%BD%D0%B5%D1%82%D0%B5-%D0%B8%D0%BD%D1%82"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Если вы покинете интерпритатор и позже откроете новый интерактивный сеанс, вы получите тот же порядок элементов:</div></div></div></div></div>```python
>>> # Python 2.7. New interactive session
>>> a_dict = {'color': 'blue', 'fruit': 'apple', 'pet': 'dog'}
>>> a_dict
{'color': 'blue', 'pet': 'dog', 'fruit': 'apple'}
>>> a_dict
{'color': 'blue', 'pet': 'dog', 'fruit': 'apple'}
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%91%D0%BE%D0%BB%D0%B5%D0%B5-%D0%B2%D0%BD%D0%B8%D0%BC%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5-%D1%80"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Более внимательное рассмотрение этих двух выходных данных показывает, что результирующий порядок в обоих случаях одинаков. Вот почему вы можете сказать, что порядок является детерминированным.</div></div></div></div></div>В Python 3.5 словари все еще неупорядочены, но на этот раз **рандомизированные** структуры данных. Это означает, что каждый раз, когда вы снова запускаете словарь, вы получаете другой порядок элементов. Давайте посмотрим:

```python
>>> # Python 3.5
>>> a_dict = {'color': 'blue', 'fruit': 'apple', 'pet': 'dog'}
>>> a_dict
{'color': 'blue', 'pet': 'dog', 'fruit': 'apple'}
>>> a_dict
{'color': 'blue', 'pet': 'dog', 'fruit': 'apple'}
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%95%D1%81%D0%BB%D0%B8-%D0%B2%D1%8B-%D0%B2%D0%BE%D0%B9%D0%B4%D0%B5%D1%82%D0%B5-%D0%B2-%D0%BD%D0%BE"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Если вы войдете в новый интерактивный сеанс, вы получите следующее:</div></div></div></div></div>```python
>>> # Python 3.5. New interactive session
>>> a_dict = {'color': 'blue', 'fruit': 'apple', 'pet': 'dog'}
>>> a_dict
{'fruit': 'apple', 'pet': 'dog', 'color': 'blue'}
>>> a_dict
{'fruit': 'apple', 'pet': 'dog', 'color': 'blue'}
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%9D%D0%B0-%D1%8D%D1%82%D0%BE%D1%82-%D1%80%D0%B0%D0%B7-%D0%B2%D1%8B-%D0%BC%D0%BE%D0%B6%D0%B5%D1%82"><div class="enlighter-code"><div class="enlighter"><div class=""><div>На этот раз вы можете видеть, что порядок элементов отличается на обоих выходах. Вот почему вы можете сказать, что это рандомизированные структуры данных.</div></div></div></div></div>В Python 3.6 и более **поздних версиях словари являются упорядоченными структурами данных**, что означает, что они хранят свои элементы в том же порядке, в котором они были созданы, как вы можете видеть здесь:

```python
>>> # Python 3.6 and beyond
>>> a_dict = {'color': 'blue', 'fruit': 'apple', 'pet': 'dog'}
>>> a_dict
{'color': 'blue', 'fruit': 'apple', 'pet': 'dog'}
>>> a_dict
{'color': 'blue', 'fruit': 'apple', 'pet': 'dog'}
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%AD%D1%82%D0%BE-%D0%BE%D1%82%D0%BD%D0%BE%D1%81%D0%B8%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE-%D0%BD%D0%BE%D0%B2"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Это относительно новая функция словарей Python, и она очень полезна. Но если вы пишете код, который может быть запущен в разных версиях Python, вы не должны полагаться на этот функционал, поскольку он может генерировать некорректное поведение.</div></div></div></div></div><div class="code-block code-block-3" id="bkmrk-" style="margin: 8px 0; clear: both;">  
</div>Другой важной особенностью словарей является то, что они являются изменчивыми структурами данных, что означает, что вы можете добавлять, удалять и обновлять их элементы. Стоит отметить, что это также означает, что их нельзя использовать в качестве ключей для других словарей, так как они не являются объектами, которые можно хэшировать.

**Примечание**. Все, что описано в этом разделе, относится к базовой реализации Python, CPython.

Другие реализации Python, такие как [PyPy](https://pypy.org/features.html), [IronPython](http://ironpython.net/) или [Jython](http://www.jython.org/index.html), могут демонстрировать другое поведение словаря, которые выходят за рамки данной статьи.

## Как перебирать словарь в Python: основы

Словари являются полезной и широко используемой структурой данных в Python. Как программист Python, вы часто будете в ситуациях, когда вам придется перебирать словарь, в то время как вы выполняете некоторые действия над его парами ключ-значение.

Когда дело доходит до перебора словаря в Python, язык предоставляет вам несколько отличных инструментов, которые мы рассмотрим в этой статье.

### Прямая итерация по ключам

Словари Python являются [отображающими объектами](https://docs.python.org/3/glossary.html#term-mapping). Это означает, что они наследуют некоторые **специальные методы**, которые Python внутренне использует для выполнения некоторых операций. Эти методы называются с использованием соглашения об именах, заключающегося в добавлении двойного подчеркивания в начале и в конце имени метода.

Чтобы визуализировать методы и атрибуты любого объекта Python, вы можете использовать **dir()**, которая является встроенной функцией. Если вы запустите **dir()** с пустым словарем в качестве аргумента, вы сможете увидеть все методы и атрибуты, которые реализуют словари:

```python
>>> dir({})
['__class__', '__contains__', '__delattr__', ... , '__iter__', ...]
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%95%D1%81%D0%BB%D0%B8-%D0%B2%D1%8B-%D0%B2%D0%BD%D0%B8%D0%BC%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE-"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Если вы внимательно посмотрите на предыдущий вывод, вы увидите **\_\_iter\_\_**. Это метод, который вызывается, когда для контейнера требуется итератор, и он должен возвращать новый объект итератора, который может выполнять итерацию по всем объектам в контейнере.</div></div></div></div></div>**Примечание**: вывод предыдущего кода был сокращен (…) для экономии места.

Для мапинга (например, словарей) **.\_\_iter\_\_()** должен перебирать ключи. Это означает, что если вы поместите словарь непосредственно в цикл `<a aria-label=" (откроется в новой вкладке)" href="https://realpython.com/python-for-loop/" rel="noreferrer noopener" target="_blank">for</a>`, Python автоматически вызовет **.\_\_iter\_\_()** для этого словаря, и вы получите итератор по его ключам:

```python
>>> a_dict = {'color': 'blue', 'fruit': 'apple', 'pet': 'dog'}
>>> for key in a_dict:
... print(key)
...
color
fruit
pet
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-python-%D0%B4%D0%BE%D1%81%D1%82%D0%B0%D1%82%D0%BE%D1%87%D0%BD%D0%BE-%D1%83%D0%BC"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Python достаточно умен, чтобы знать, что **a\_dict** – это словарь и что он реализует **.\_\_iter\_\_()**. В этом примере Python автоматически вызывает **.\_\_iter\_\_(),** и это позволяет вам перебирать ключи **a\_dict**.</div></div></div></div></div>Это самый простой способ перебора словаря в Python. Просто поместите его прямо в цикл **for**, и все готово!

Если вы используете этот подход вместе с небольшой уловкой, то вы можете обрабатывать ключи и значения любого словаря. Хитрость заключается в использовании оператора индексации \[\] со словарем и его ключами для получения доступа к значениям:

```python
>>> for key in a_dict:
... print(key, '->', a_dict[key])
...
color -> blue
fruit -> apple
pet -> dog
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%9F%D1%80%D0%B5%D0%B4%D1%8B%D0%B4%D1%83%D1%89%D0%B8%D0%B9-%D0%BA%D0%BE%D0%B4-%D0%BF%D0%BE%D0%B7%D0%B2%D0%BE"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Предыдущий код позволил вам получить доступ к ключам (**key**) и значениям (**a\_dict\[key\]**) **a\_dict** одновременно. Таким образом, вы можете выполнить любую операцию как с ключами, так и со значениями.</div></div></div></div></div>### Итерация по .items()

Когда вы работаете со словарями, вероятно, вы захотите работать как с ключами, так и со значениями. Одним из наиболее полезных способов перебора словаря в Python является использование метода **.items()**, который возвращает новый [вид](https://docs.python.org/3/library/stdtypes.html#dict-views) элементов словаря:

```python
>>> a_dict = {'color': 'blue', 'fruit': 'apple', 'pet': 'dog'}
>>> d_items = a_dict.items()
>>> d_items # Here d_items is a view of items
dict_items([('color', 'blue'), ('fruit', 'apple'), ('pet', 'dog')])
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%9F%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F-%D1%81%D0%BB%D0%BE%D0%B2%D0%B0%D1%80"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Представления словаря, такое как **d\_items**, обеспечивают динамическое представление записей словаря, что означает, что при изменении словаря представления отражают эти изменения.</div></div></div></div></div>Представления могут быть перебраны для получения соответствующих данных, поэтому вы можете итерировать словарь в Python, используя объект представления, возвращаемый **.items()**:

```python
>>> for item in a_dict.items():
... print(item)
...
('color', 'blue')
('fruit', 'apple')
('pet', 'dog')
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82-%D0%BF%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Объект представления, возвращаемый функцией **.items()**, выдает пары ключ-значение по одной и позволяет перебирать словарь, и таким образом, вы получаете доступ к ключам и значениям одновременно.</div></div></div></div></div>Если вы присмотритесь к отдельным элементам, полученным с помощью **.items()**, вы заметите, что они действительно являются кортежами объектов. Давайте посмотрим:

```python
>>> for item in a_dict.items():
... print(item)
... print(type(item))
...
('color', 'blue')
<class 'tuple'>
('fruit', 'apple')
<class 'tuple'>
('pet', 'dog')
<class 'tuple'>
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%92%D1%8B-%D0%BC%D0%BE%D0%B6%D0%B5%D1%82%D0%B5-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Вы можете использовать распаковку кортежей для перебора ключей и значений словаря. Для этого вам просто нужно распаковать элементы каждого элемента в две разные переменные, представляющие ключ и значение:</div></div></div></div></div>```python
>>> for key, value in a_dict.items():
... print(key, '->', value)
...
color -> blue
fruit -> apple
pet -> dog
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%97%D0%B4%D0%B5%D1%81%D1%8C%2C-%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D1%8B%D0%B5-ke"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Здесь, переменные **key** и **value** в заголовке вашего цикла **for** распаковываются. Каждый раз, когда цикл запускается, **key** будет хранить ключ, а **value** будет хранить значение элемента, который был обработан. Таким образом, у вас будет больше контроля над элементами словаря, и вы сможете обрабатывать ключи и значения отдельно.</div></div></div></div></div>**Примечание**: обратите внимание, что **.values()** и **.keys()** возвращают объекты представления так же, как **.items()**, как вы увидите в следующих двух разделах.

### Итерация через .keys()

Если вам просто нужно работать с ключами словаря, то вы можете использовать метод **.keys()**, который возвращает новый объект представления, содержащий ключи словаря:

```python
>>> a_dict = {'color': 'blue', 'fruit': 'apple', 'pet': 'dog'}
>>> keys = a_dict.keys()
>>> keys
dict_keys(['color', 'fruit', 'pet'])
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%A7%D1%82%D0%BE%D0%B1%D1%8B-%D0%BF%D0%B5%D1%80%D0%B5%D0%B1%D1%80%D0%B0%D1%82%D1%8C-%D1%81%D0%BB%D0%BE%D0%B2"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Чтобы перебрать словарь в Python с помощью **.keys()**, вам просто нужно вызвать **.keys()** в заголовке цикла for:</div></div></div></div></div>```python
>>> for key in a_dict.keys():
... print(key)
...
color
fruit
pet
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%98%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D1%83%D1%8F-%D1%82%D0%BE%D1%82-%D0%B6%D0%B5-%D1%82%D1%80%D1%8E"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Используя тот же трюк, который вы видели ранее (оператор индексации []), вы можете получить доступ к значениям словаря:</div></div></div></div></div>```python
>>> for key in a_dict.keys():
... print(key, '->', a_dict[key])
...
color -> blue
fruit -> apple
pet -> dog
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%A2%D0%B0%D0%BA%D0%B8%D0%BC-%D0%BE%D0%B1%D1%80%D0%B0%D0%B7%D0%BE%D0%BC%2C-%D0%B2%D1%8B-%D0%BF%D0%BE"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Таким образом, вы получите доступ к ключам (**key**) и значениям (**a\_dict\[key\]**) **a\_dict** одновременно, и вы сможете выполнять с ними любые действия.</div></div></div></div></div>### Итерация по .values()

Также можно использовать значения для перебора словаря. Один из способов сделать это – использовать **.values()**, который возвращает представление со значениями словаря:

```python
>>> a_dict = {'color': 'blue', 'fruit': 'apple', 'pet': 'dog'}
>>> values = a_dict.values()
>>> values
dict_values(['blue', 'apple', 'dog'])
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%92-%D0%BF%D1%80%D0%B5%D0%B4%D1%8B%D0%B4%D1%83%D1%89%D0%B5%D0%BC-%D0%BA%D0%BE%D0%B4%D0%B5-va"><div class="enlighter-code"><div class="enlighter"><div class=""><div>В предыдущем коде **values** содержит ссылку на объект представления, содержащий значения **a\_dict**.</div></div></div></div></div>Как и любой объект представления, объект, возвращаемый функцией **.values()**, также может быть итерирован. В этом случае **.values()** возвращает значения **a\_dict**:

```python
>>> for value in a_dict.values():
... print(value)
...
blue
apple
dog
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%A1%D1%82%D0%BE%D0%B8%D1%82-%D0%BE%D1%82%D0%BC%D0%B5%D1%82%D0%B8%D1%82%D1%8C%2C-%D1%87%D1%82%D0%BE-"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Стоит отметить, что методы **keys()** и **values()** также поддерживают тесты членства (in) ([membership tests (](https://docs.python.org/3/library/stdtypes.html#typesseq-common)`<a aria-label=" (откроется в новой вкладке)" href="https://docs.python.org/3/library/stdtypes.html#typesseq-common" rel="noreferrer noopener" target="_blank">in</a>`[)](https://docs.python.org/3/library/stdtypes.html#typesseq-common)), что является важной функцией, если вы пытаетесь узнать, есть ли определенный элемент в словаре или нет:</div></div></div></div></div>```python
>>> a_dict = {'color': 'blue', 'fruit': 'apple', 'pet': 'dog'}
>>> 'pet' in a_dict.keys()
True
>>> 'apple' in a_dict.values()
True
>>> 'onion' in a_dict.values()
False
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%9F%D1%80%D0%BE%D0%B2%D0%B5%D1%80%D0%BA%D0%B0-%D1%87%D0%BB%D0%B5%D0%BD%D1%81%D1%82%D0%B2%D0%B0-%D1%81-"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Проверка членства с помощью **in** возвращает **True**, если ключ (или значение или элемент) присутствует в тестируемом словаре, и возвращает **False** в противном случае. Тест на членство позволяет вам не выполнять итерацию по словарю в Python, если вы просто хотите узнать, присутствует ли определенный словарь (или значение, или элемент) в словаре или нет.</div></div></div></div></div>## Изменение значений и ключей

Часто бывает необходимо изменить значения и ключа, когда вы перебираете словарь в Python. Есть некоторые моменты, которые вы должны принять во внимание, чтобы выполнить эту задачу.

Например, значения можно изменять всякий раз, когда вам нужно, но вам нужно будет использовать исходный словарь и ключ, который отображает значение, которое вы хотите изменить:

```python
>>> prices = {'apple': 0.40, 'orange': 0.35, 'banana': 0.25}
>>> for k, v in prices.items():
... prices[k] = round(v * 0.9, 2) # Apply a 10% discount
...
>>> prices
{'apple': 0.36, 'orange': 0.32, 'banana': 0.23}
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%92-%D1%8D%D1%82%D0%BE%D0%BC-%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D0%B5-%D0%BA%D0%BE%D0%B4%D0%B0%2C"><div class="enlighter-code"><div class="enlighter"><div class=""><div>В этом примере кода, чтобы изменить значения **prices** и применить скидку 10%, мы использовали выражение **prices\[k\] = round(v \* 0.9, 2)**.</div></div></div></div></div>Так зачем вам использовать оригинальный словарь, если у вас есть доступ к его ключу (**k)** и его значениям (**v**)? Если мы можем изменить их напрямую?

Реальная проблема заключается в том, что изменения **k** и **v** не отражаются в исходном словаре. То есть, если вы измените какой-либо из них (**k** или **v**) непосредственно внутри цикла, то, что действительно происходит, так это то, что вы потеряете ссылку на соответствующий компонент словаря, не изменяя ничего в словаре.

С другой стороны, ключи могут быть добавлены или удалены из словаря путем преобразования представления, возвращаемого функцией **.keys()**, в объект **list**:

```python
>>> prices = {'apple': 0.40, 'orange': 0.35, 'banana': 0.25}
>>> for key in list(prices.keys()): # Use a list instead of a view
... if key == 'orange':
... del prices[key] # Delete a key from prices
...
>>> prices
{'apple': 0.4, 'banana': 0.25}
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%AD%D1%82%D0%BE%D1%82-%D0%BF%D0%BE%D0%B4%D1%85%D0%BE%D0%B4-%D0%BC%D0%BE%D0%B6%D0%B5%D1%82-%D0%B8%D0%BC"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Этот подход может иметь некоторые последствия для производительности, в основном связанные с потреблением памяти. Например, вместо объекта просмотра, который выдает элементы по требованию, у вас будет полный новый **list** в памяти вашей системы. Тем не менее, это может быть безопасным способом изменения ключей при переборе словаря в Python.</div></div></div></div></div>Наконец, если вы попытаетесь удалить ключ из **prices**, используя напрямую **.keys()**, тогда Python вызовет **RuntimeError**, сообщающую, что размер словаря изменился во время итерации:

```python
>>> # Python 3. dict.keys() returns a view object, not a list
>>> prices = {'apple': 0.40, 'orange': 0.35, 'banana': 0.25}
>>> for key in prices.keys():
... if key == 'orange':
... del prices[key]
...
Traceback (most recent call last):
File "<input>", line 1, in <module>
for key in prices.keys():
RuntimeError: dictionary changed size during iteration
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%AD%D1%82%D0%BE-%D0%BF%D0%BE%D1%82%D0%BE%D0%BC%D1%83%2C-%D1%87%D1%82%D0%BE-.key"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Это потому, что **.keys()** возвращает объект словаря-представления, который выдает ключи по запросу по одному, и если вы удаляете элемент (**del values \[key\]**), то Python вызывает **RuntimeError**, потому что вы изменили словарь во время итерации.</div></div></div></div></div><div class="code-block code-block-3" id="bkmrk--1" style="margin: 8px 0; clear: both;">  
</div>**Примечание**. В Python 2 объекты **.items()**, **.keys()** и **.values()** возвращают список объектов. Но **.iteritems()**, **iterkeys()** и **.itervalues()** возвращают итераторы. Итак, если вы используете Python 2, то вы можете изменить ключи словаря, используя **.keys()** напрямую.

С другой стороны, если вы используете **iterkeys()** в своем коде Python 2 и пытаетесь изменить ключи словаря, вы получите **RuntimeError**.

## Примеры из реального мира

До сих пор вы видели более простые способы перебора словаря в Python. Теперь пришло время посмотреть, как вы можете выполнять некоторые действия с элементами словаря во время итерации. Давайте посмотрим на некоторые примеры из реальной жизни.

**Примечание**. Позже в этой статье вы увидите другой способ решения тех же самых проблем с помощью других инструментов Python.

### Превращение ключей в значение и наоборот

Предположим, у вас есть словарь и по какой-то причине необходимо превратить ключи в значения и наоборот. В этой ситуации вы можете использовать цикл **for** для перебора словаря и создания нового словаря, используя ключи в качестве значений и наоборот:

```python
>>> a_dict = {'one': 1, 'two': 2, 'thee': 3, 'four': 4}
>>> new_dict = {}
>>> for key, value in a_dict.items():
... new_dict[value] = key
...
>>> new_dict
{1: 'one', 2: 'two', 3: 'thee', 4: 'four'}
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%92%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5-new_dict%5Bv"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Выражение **new\_dict\[value\] = key** сделает всю работу за вас, превратив ключи в значения и используя значения в качестве ключей. Чтобы этот код работал, данные, хранящиеся в исходных значениях, должны иметь тип данных, который можно хэшировать.</div></div></div></div></div>### Фильтрация

Иногда вы будете в ситуациях, когда у вас есть словарь, и вы захотите создать новый, чтобы хранить только данные, которые удовлетворяют заданному условию. Вы можете сделать это с помощью **if** внутри цикла **for** следующим образом:

```python
>>> a_dict = {'one': 1, 'two': 2, 'thee': 3, 'four': 4}
>>> new_dict = {} # Create a new empty dictionary
>>> for key, value in a_dict.items():
... # If value satisfies the condition, then store it in new_dict
... if value <= 2:
... new_dict[key] = value
...
>>> new_dict
{'one': 1, 'two': 2}
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%92-%D1%8D%D1%82%D0%BE%D0%BC-%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D0%B5-%D0%B2%D1%8B-%D0%BE%D1%82"><div class="enlighter-code"><div class="enlighter"><div class=""><div>В этом примере вы отфильтровали элементы со значением больше 2. Теперь **new\_dict** содержит только элементы, которые удовлетворяют условному значению &lt;= 2. Это одно из возможных решений для такого рода проблем. Позже вы увидите более понятный и понятный способ получить тот же результат.</div></div></div></div></div>### Выполнять некоторые расчеты

Также часто требуется выполнять некоторые вычисления, пока вы перебираете словарь в Python. Предположим, вы сохранили данные о продажах вашей компании в словаре, и теперь вы хотите узнать общий доход за год.

Чтобы решить эту проблему, вы можете определить переменную с начальным значением ноль. Затем вы можете накапливать каждое значение вашего словаря в этой переменной:

```python
>>> incomes = {'apple': 5600.00, 'orange': 3500.00, 'banana': 5000.00}
>>> total_income = 0.00
>>> for value in incomes.values():
... total_income += value # Accumulate the values in total_income
...
>>> total_income
14100.0
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%97%D0%B4%D0%B5%D1%81%D1%8C-%D0%B2%D1%8B-%D0%BF%D1%80%D0%BE%D1%81%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D0%B2%D0%B0"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Здесь вы просматривали **incomes** и последовательно накапливали их значения в **total\_income**, как и хотели. Выражение **total\_income += value** делает все работу, и в конце цикла вы получите общий доход за год. Обратите внимание, что **total\_income += value** эквивалентно **total\_income = total\_income + value**.</div></div></div></div></div>## Использование генераторов (comprehensions)

**Генераторы словарей** (**Dictionary comprehension**) – это компактный способ обработки всех или части элементов в коллекции и возврата словаря в качестве результата. В отличие от списочных представлений, им нужны два выражения, разделенные двоеточием, за которым следуют предложения **for** и **if** (необязательно). Когда выполняется генератор словаря, полученные пары ключ-значение вставляются в новый словарь в том же порядке, в котором они были созданы.

Предположим, например, что у вас есть два списка данных, и вам нужно создать новый словарь из них. В этом случае вы можете использовать zip (\* iterables) в Python для циклического обхода элементов обоих списков:

```python
>>> objects = ['blue', 'apple', 'dog']
>>> categories = ['color', 'fruit', 'pet']
>>> a_dict = {key: value for key, value in zip(categories, objects)}
>>> a_dict
{'color': 'blue', 'fruit': 'apple', 'pet': 'dog'}
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%97%D0%B4%D0%B5%D1%81%D1%8C-zip%28%29-%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B0%D0%B5%D1%82"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Здесь **zip()** получает два итерируемых объекта categories и objects в качестве аргументов и создает итератор, который объединяет элементы из каждого объекта. Объекты кортежа, сгенерированные zip(), затем распаковываются в ключ и значение, которые в итоге используются для создания нового словаря.</div></div></div></div></div>Генератор словарей открывает широкий спектр новых возможностей и предоставляет вам отличный инструмент для перебора словаря в Python.

### Еще раз о превращение ключей в значение и наоборот

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

```python
>>> a_dict = {'one': 1, 'two': 2, 'thee': 3, 'four': 4}
>>> new_dict = {value: key for key, value in a_dict.items()}
>>> new_dict
{1: 'one', 2: 'two', 3: 'thee', 4: 'four'}
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%A1-%D0%B3%D0%B5%D0%BD%D0%B5%D1%80%D0%B0%D1%82%D0%BE%D1%80%D0%BE%D0%BC-%D1%81%D0%BB%D0%BE%D0%B2%D0%B0%D1%80"><div class="enlighter-code"><div class="enlighter"><div class=""><div>С генератором словаря вы создали совершенно новый словарь, в котором ключи заняли место значений, и наоборот. Этот новый подход дал вам возможность писать более читабельный, лаконичный, эффективный и Pythonic код.</div></div></div></div></div>Условие для работы этого кода такое же, как вы видели ранее: значения должны быть объектами, которые можно хэшировать. В противном случае вы не сможете использовать их в качестве ключей для **a\_dict**.

### Пересмотр фильтрации

Чтобы отфильтровать элементы в словаре с генератором, вам просто нужно добавить условие **if**, которое определяет условие, которое вы хотите выполнить. В предыдущем примере, когда вы фильтровали словарь, это условие было, если v &lt;= 2. С этим условием **if**, добавленным в конец генератора словаря, вы отфильтруете элементы, значения которых больше 2. Давайте посмотрим:

```python
>>> a_dict = {'one': 1, 'two': 2, 'thee': 3, 'four': 4}
>>> new_dict = {k: v for k, v in a_dict.items() if v <= 2}
>>> new_dict
{'one': 1, 'two': 2}
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%A2%D0%B5%D0%BF%D0%B5%D1%80%D1%8C-new_dict-%D1%81%D0%BE%D0%B4%D0%B5"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Теперь **new\_dict** содержит только элементы, которые удовлетворяют вашему условию. По сравнению с предыдущими решениями, это код более Pythonic и эффективный.</div></div></div></div></div><div class="code-block code-block-3" id="bkmrk--2" style="margin: 8px 0; clear: both;">  
</div>### Пересмотр выполнение расчетов

Помните пример с продажами компании? Если вы используете генератор списков (**list comprehension**) для перебора значений словаря, вы получите более компактный, быстрый и Pythonic-код:

```python
>>> incomes = {'apple': 5600.00, 'orange': 3500.00, 'banana': 5000.00}
>>> total_income = sum([value for value in incomes.values()])
>>> total_income
14100.0
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%93%D0%B5%D0%BD%D0%B5%D1%80%D0%B0%D1%82%D0%BE%D1%80-%D1%81%D0%BF%D0%B8%D1%81%D0%BA%D0%BE%D0%B2-%D1%81%D0%BE"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Генератор списков создал объект **list**, содержащий значения **incomes**, а затем мы суммировали их все с помощью функции **sum()** и сохранили результат в **total\_income**.</div></div></div></div></div>Если вы работаете с действительно большим словарем, и использование памяти является проблемой для вас, тогда вы можете использовать **выражение-генератор** (**generator expression**) вместо генератора списков. **выражение-генератор** – это выражение, которое возвращает итератор. Это похоже на генератор списков, но вместо квадратных скобок для его определения необходимо использовать круглые скобки:

```python
>>> total_income = sum(value for value in incomes.values())
>>> total_income
14100.0
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%A2%D0%BE-%D0%B5%D1%81%D1%82%D1%8C-%D0%B5%D1%81%D0%BB%D0%B8-%D0%B2%D1%8B-%D0%BF%D0%BE%D0%BC%D0%B5"><div class="enlighter-code"><div class="enlighter"><div class=""><div>То есть если вы поменяете квадратные скобки для пары круглых скобок (здесь круглые скобки sum()), вы превратите генератор списков в выражение-генератор, и ваш код будет более эффективным в памяти, потому что выражение-генератор использует элементы по запросу. Вместо того, чтобы создавать и хранить весь список в памяти, он будет хранить только один элемент за раз.</div></div></div></div></div>**Примечание**. Если вы новичок в выражение-генератор (generator expressions), вы можете взглянуть на [Introduction to Python Generators](https://realpython.com/introduction-to-python-generators/), чтобы лучше изучить тему.

Наконец, есть более простой способ решить эту проблему, просто используя **incomes.values()** непосредственно в качестве аргумента для **sum()**:

```python
>>> total_income = sum(incomes.values())
>>> total_income
14100.0
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-sum%28%29-%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B0%D0%B5%D1%82-%D0%B2-%D0%BA%D0%B0%D1%87"><div class="enlighter-code"><div class="enlighter"><div class=""><div>**sum()** получает в качестве аргумента итерацию и возвращает общую сумму его элементов. Здесь **incomes.values()** играет роль итерируемого значения, переданного в sum(). Результат – общий доход, который вы искали.</div></div></div></div></div>### Удаление выбранных элементов

Теперь предположим, что у вас есть словарь, и вам нужно создать новый с удаленными выбранными ключами. Помните, как объекты словаря похожи на [sets](https://realpython.com/python-sets/)? Эти сходства выходят за рамки просто коллекции хэшируемых и уникальных объектов. Эти объекты также поддерживают общие операции над множествами. Давайте посмотрим, как вы можете воспользоваться этим, чтобы удалить определенные элементы из словаря:

```python
>>> incomes = {'apple': 5600.00, 'orange': 3500.00, 'banana': 5000.00}
>>> non_citric = {k: incomes[k] for k in incomes.keys() - {'orange'}}
>>> non_citric
{'apple': 5600.0, 'banana': 5000.0}
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%AD%D1%82%D0%BE%D1%82-%D0%BA%D0%BE%D0%B4-%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D0%B5%D1%82%2C-%D0%BF"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Этот код работает, потому что элементы словаря поддерживают операции над множествами, такие как объединения, пересечения и различия. Когда вы написали **incomes.keys () – {‘orange’}**, вы выполняли операцию с заданным различием. Если вам нужно выполнить какие-либо операции над множествами с ключами словаря, то вы можете просто использовать элементы напрямую, без предварительного преобразования его в set.</div></div></div></div></div>### Сортировка словаря

Часто необходимо сортировать элементы коллекции. Начиная с Python 3.6, словари являются упорядоченными структурами данных, поэтому, если вы используете Python 3.6 (и более поздние версии), вы сможете сортировать элементы любого словаря с помощью **sorted()** и с помощью генератора словаря:

```python
>>> # Python 3.6, and beyond
>>> incomes = {'apple': 5600.00, 'orange': 3500.00, 'banana': 5000.00}
>>> sorted_income = {k: incomes[k] for k in sorted(incomes)}
>>> sorted_income
{'apple': 5600.0, 'banana': 5000.0, 'orange': 3500.0}
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%AD%D1%82%D0%BE%D1%82-%D0%BA%D0%BE%D0%B4-%D0%BF%D0%BE%D0%B7%D0%B2%D0%BE%D0%BB%D1%8F%D0%B5%D1%82-%D1%81"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Этот код позволяет создать новый словарь с ключами в отсортированном порядке. Это возможно, потому что **sorted(incomes)** возвращает список отсортированных ключей, которые можно использовать для создания нового словаря **sorted\_dict**.</div></div></div></div></div>## Итерация в отсортированном порядке

Иногда вам может понадобиться перебрать словарь в Python, но вы хотите сделать это в отсортированном порядке. Это может быть достигнуто с помощью **sorted()**. Когда вы вызываете **sorted(iterable)**, вы получаете list с элементами в отсортированном порядке.

Давайте посмотрим, как вы можете использовать **sorted()** для перебора словаря, когда вам нужно сделать это в отсортированном порядке.

### Сортировка по ключам

Если вам нужно перебрать словарь в Python и отсортировать его по ключам, вы можете использовать свой словарь в качестве аргумента для **sorted()**. Это вернет list, содержащий ключи в отсортированном порядке, и вы сможете их перебирать:

```python
>>> incomes = {'apple': 5600.00, 'orange': 3500.00, 'banana': 5000.00}
>>> for key in sorted(incomes):
... print(key, '->', incomes[key])
...
apple -> 5600.0
banana -> 5000.0
orange -> 3500.0
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%92-%D1%8D%D1%82%D0%BE%D0%BC-%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D0%B5-%D0%B2%D1%8B-%D0%BE%D1%82-1"><div class="enlighter-code"><div class="enlighter"><div class=""><div>В этом примере вы отсортировали словарь (в алфавитном порядке) по ключам, используя **sorted(incomes)** в заголовке цикла **for**. Обратите внимание, что вы также можете использовать **sorted(incomes.keys())**, чтобы получить тот же результат. В обоих случаях вы получите список, содержащий ключи вашего словаря в отсортированном порядке.</div></div></div></div></div>**Примечание**. Порядок сортировки будет зависеть от типа данных, который вы используете для ключей или значений, и от внутренних правил, которые Python использует для сортировки этих типов данных.

### Сортировка по значениям

Вам также может понадобиться перебрать словарь в Python с его элементами, отсортированными по значениям. Вы также можете использовать **sorted()**, но со вторым аргументом **key**.

Аргумент **key** определяет функцию одного аргумента, которая используется для извлечения ключа сравнения для каждого элемента, который вы обрабатываете.

Чтобы отсортировать элементы словаря по значениям, вы можете написать функцию, которая возвращает значение каждого элемента, и использовать эту функцию в **key** аргумента для **sorted()**:

```python
>>> incomes = {'apple': 5600.00, 'orange': 3500.00, 'banana': 5000.00}
>>> def by_value(item):
... return item[1]
...
>>> for k, v in sorted(incomes.items(), key=by_value):
... print(k, '->', v)
...
('orange', '->', 3500.0)
('banana', '->', 5000.0)
('apple', '->', 5600.0)
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%92-%D1%8D%D1%82%D0%BE%D0%BC-%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D0%B5-%D0%BC%D1%8B-%D0%BE%D0%BF"><div class="enlighter-code"><div class="enlighter"><div class=""><div>В этом примере мы определили **by\_value()** и использовали его для сортировки **incomes** по значению. Затем мы перебираем словарь в порядке сортировки, используя **sorted()**. Ключевая функция (**by\_value ()**) сообщает **sorted()** отсортировать **incomes.items()** по второму элементу каждого элемента, то есть по значению (**item \[1\]**).</div></div></div></div></div><div class="code-block code-block-3" id="bkmrk--3" style="margin: 8px 0; clear: both;">  
</div>Вы также можете просто перебирать значения словаря в отсортированном порядке, не беспокоясь о ключах. В этом случае вы можете использовать **.values()** следующим образом:

```python
>>> for value in sorted(incomes.values()):
... print(value)
...
3500.0
5000.0
5600.0
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-sorted%28comes.values-"><div class="enlighter-code"><div class="enlighter"><div class=""><div>**sorted(comes.values ())** возвращает значения словаря в отсортированном порядке по вашему желанию. Ключи не будут доступны, если вы используете **incomes.values()**, но иногда вам не нужны ключи, только значения, и это быстрый способ получить к ним доступ.</div></div></div></div></div>### Реверсия

Если вам нужно отсортировать словари в обратном порядке, вы можете добавить **reverse = True** в качестве аргумента для **sorted()**. Ключевое слово аргумент **reverse** должно принимать логическое значение. Если установлено значение **True**, то элементы сортируются в обратном порядке:

```python
>>> incomes = {'apple': 5600.00, 'orange': 3500.00, 'banana': 5000.00}
>>> for key in sorted(incomes, reverse=True):
... print(key, '->', incomes[key])
...
orange -> 3500.0
banana -> 5000.0
apple -> 5600.0
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%97%D0%B4%D0%B5%D1%81%D1%8C-%D0%B2%D1%8B-%D0%BF%D0%B5%D1%80%D0%B5%D0%B1%D0%B8%D1%80%D0%B0%D0%BB%D0%B8-"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Здесь вы перебирали ключи доходов в обратном порядке, используя **sorted(incomes, reverse=True)** в заголовке цикла **for**.</div></div></div></div></div>Наконец, важно отметить, что **sorted()** не меняет порядок основного словаря. Что на самом деле происходит, так это то, что **sorted()** создает независимый список со своими элементами в отсортированном порядке, поэтому **incomes** остаются прежними:

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%3E%3E%3E-incomes-%7B%27apple%27"><div class="enlighter-code"><div class="enlighter"><div class=""><div><span class="enlighter-g1">&gt;&gt;&gt;</span><span class="enlighter-text"> incomes</span></div></div><div class=""><div><span class="enlighter-g1">{</span><span class="enlighter-s0">'apple'</span><span class="enlighter-text">: </span><span class="enlighter-n0">5600.0</span><span class="enlighter-text">, </span><span class="enlighter-s0">'orange'</span><span class="enlighter-text">: </span><span class="enlighter-n0">3500.0</span><span class="enlighter-text">, </span><span class="enlighter-s0">'banana'</span><span class="enlighter-text">: </span><span class="enlighter-n0">5000.0</span><span class="enlighter-g1">}</span></div></div></div></div></div>## Разрушительная итерация с помощью .popitem()

Иногда нужно перебрать словарь в Python и последовательно удалить его элементы. Для выполнения этой задачи можно использовать **.popitem()**, которая удалит и возвратит произвольную пару ключ-значение из словаря. С другой стороны, когда вы вызываете **.popitem()** в пустом словаре, он вызывает ошибку **KeyError**.

Пример:

```python
# File: dict_popitem.py

a_dict = {'color': 'blue', 'fruit': 'apple', 'pet': 'dog'}

while True:
try:
print(f'Dictionary length: {len(a_dict)}')
item = a_dict.popitem()
# Do something with item here...
print(f'{item} removed')
except KeyError:
print('The dictionary has no item now...')
break
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%92%D0%BD%D1%83%D1%82%D1%80%D0%B8-%D1%86%D0%B8%D0%BA%D0%BB%D0%B0-while-%D0%BC"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Внутри цикла **while** мы определили блок **try…except** для того, чтобы поймать **KeyError**, сгенерированный функцией **.popitems()**, когда **a\_dict** станет пустым. В блоке **try…except** мы обрабатываем словарь, удаляя элемент в каждой итерации. Переменная **item** хранит ссылку на последующие элементы и позволяет нам выполнять с ними некоторые действия.</div></div></div></div></div>Если мы [запустим этот скрипт из командной строки](https://realpython.com/run-python-scripts), то мы получим следующие результаты:

```python
$ python3 dict_popitem.py
Dictionary length: 3
('pet', 'dog') removed
Dictionary length: 2
('fruit', 'apple') removed
Dictionary length: 1
('color', 'blue') removed
Dictionary length: 0
The dictionary has no item now...
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%97%D0%B4%D0%B5%D1%81%D1%8C-.popitem%28%29-%D0%BF%D0%BE%D1%81"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Здесь **.popitem()** последовательно удаляет элементы из **a\_dict**. Цикл прервался, когда словарь стал пустым, и **.popitem()** вызвал исключение **KeyError**.</div></div></div></div></div>## Использование некоторых из встроенных функций Python

Python предоставляет некоторые встроенные функции, которые могут быть полезны при работе со словарями. Эти функции являются своего рода инструментом итерации, который предоставляет вам еще один способ перебора словаря. Давайте посмотрим на некоторые из них.

### map()

**map()** определяется как **map(function, iterable, …)** и возвращает итератор, который применяет функцию к каждому элементу итерируемого. Таким образом, **map()** можно рассматривать как инструмент итерации, который можно использовать для перебора словаря.

Предположим, у вас есть словарь, содержащий цены на несколько продуктов, и вам нужно применить скидку к ним. В этом случае вы можете определить функцию, которая управляет скидкой, а затем использует ее в качестве первого аргумента для **map()**. Вторым аргументом может быть **price.items()**:

```python
>>> prices = {'apple': 0.40, 'orange': 0.35, 'banana': 0.25}
>>> def discount(current_price):
... return (current_price[0], round(current_price[1] * 0.95, 2))
...
>>> new_prices = dict(map(discount, prices.items()))
>>> new_prices
{'apple': 0.38, 'orange': 0.33, 'banana': 0.24}
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%97%D0%B4%D0%B5%D1%81%D1%8C-map%28%29-%D0%BF%D0%B5%D1%80%D0%B5%D0%B1%D0%B8%D1%80%D0%B0"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Здесь **map()** перебирает элементы словаря (**prices.items()**), чтобы применить скидку 5% к каждому фрукту с помощью **discount()**. В этом случае вам нужно использовать **dict()** для создания словаря **new\_prices** из итератора, возвращаемого **map()**.</div></div></div></div></div>Обратите внимание, что **discount()** возвращает кортеж в форме (**key, value**), где **current\_price\[0\]** представляет ключ, а **round(current\_price \[1\] \* 0.95, 2)** представляет новое значение.

### filter()

filter () – это еще одна встроенная функция, которую вы можете использовать для перебора словаря и фильтрации некоторых его элементов. Эта функция определяется как **filter(function, iterable)** и возвращает итератор из тех элементов итерируемого, для которых функция возвращает значение **True**.

Предположим, вы хотите знать продукты с ценой ниже 0,40. Вам нужно определить функцию, чтобы определить, удовлетворяет ли цена этому условию, и передать ее в качестве первого аргумента для **filter()**. Вторым аргументом может быть **prices.keys()**:

```python
>>> prices = {'apple': 0.40, 'orange': 0.35, 'banana': 0.25}
>>> def has_low_price(price):
... return prices[price] < 0.4
...
>>> low_price = list(filter(has_low_price, prices.keys()))
>>> low_price
['orange', 'banana']
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%97%D0%B4%D0%B5%D1%81%D1%8C-%D0%B2%D1%8B-%D0%BF%D0%B5%D1%80%D0%B5%D0%B1%D0%B8%D1%80%D0%B0%D0%BB%D0%B8--1"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Здесь вы перебирали ключи **prices** с помощью **filter()**. Тогда **filter()** применяет **has\_low\_price()** к каждому ключу **prices**. Наконец нужно использовать **list()** для генерации списка продуктов с низкой ценой, потому что **filter()** возвращает итератор, и нам нужен объект list.</div></div></div></div></div>## Использование collections.ChainMap

`<a aria-label=" (откроется в новой вкладке)" href="https://docs.python.org/3/library/collections.html" rel="noreferrer noopener" target="_blank">collections</a>` – полезный модуль из стандартной библиотеки Python, предоставляющий специализированные типы данных контейнеров. Одним из таких типов данных является **ChainMap**, который является словарным классом для создания единого представления нескольких сопоставлений (например, словарей). С **ChainMap** вы можете сгруппировать несколько словарей вместе, чтобы создать одно обновляемое представление.

Теперь предположим, что у вас есть два (или более) словаря, и вам нужно перебирать их вместе как один. Для этого вы можете создать объект **ChainMap** и инициализировать его своими словарями:

```python
>>> from collections import ChainMap
>>> fruit_prices = {'apple': 0.40, 'orange': 0.35}
>>> vegetable_prices = {'pepper': 0.20, 'onion': 0.55}
>>> chained_dict = ChainMap(fruit_prices, vegetable_prices)
>>> chained_dict # A ChainMap object
ChainMap({'apple': 0.4, 'orange': 0.35}, {'pepper': 0.2, 'onion': 0.55})
>>> for key in chained_dict:
... print(key, '->', chained_dict[key])
...
pepper -> 0.2
orange -> 0.35
onion -> 0.55
apple -> 0.4
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk--4"><div class="enlighter-code"><div class="enlighter"><div class=""><div><span class="enlighter-n0">  
</span></div></div></div></div></div>После импорта **ChainMap** из **collections** вам необходимо создать объект **ChainMap** со словарями, которые вы хотите объединить в цепочку, а затем вы можете свободно перебирать полученный объект, как если бы вы делали это с обычным словарем.

Объекты **ChainMap** также реализуют **.keys()**, **values()** и **.items()**, как это делает стандартный словарь, поэтому вы можете использовать эти методы для итерации по словарному объекту, сгенерированному **ChainMap**, точно так же, как вы это делаете с обычным словарь:

```python
>>> for key, value in chained_dict.items():
... print(key, '->', value)
...
apple -> 0.4
pepper -> 0.2
orange -> 0.35
onion -> 0.55
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%92-%D1%8D%D1%82%D0%BE%D0%BC-%D1%81%D0%BB%D1%83%D1%87%D0%B0%D0%B5-%D0%BC%D1%8B-%D0%B2%D1%8B%D0%B7"><div class="enlighter-code"><div class="enlighter"><div class=""><div>В этом случае мы вызвали **.items()** для объекта **ChainMap**. Объект **ChainMap** вел себя так, как будто это был обычный словарь, а **.items()** возвращает объект представления словаря, который можно перебирать как обычно.</div></div></div></div></div>## Использование itertools

**Iterotools** – модуль, который предоставляет некоторые полезные инструменты для выполнения итерационных задач. Давайте посмотрим, как можно использовать некоторые из них для перебора словаря в Python.

### Циклическая итерация с помощью cycle()

Предположим, вы хотите перебрать словарь в Python, но вам нужно перебирать его несколько раз в одном цикле. Чтобы выполнить эту задачу, вы можете использовать **itertools.cycle(iterable)**, который заставляет итератор возвращать элементы из **iterable** и сохранять копию каждого из них. Когда итерация исчерпана, **cycle()** возвращает элементы из сохраненной копии. Это выполняется циклически, поэтому вы можете остановить цикл.

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

```python
>>> from itertools import cycle
>>> prices = {'apple': 0.40, 'orange': 0.35, 'banana': 0.25}
>>> times = 3 # Define how many times you need to iterate through prices
>>> total_items = times * len(prices)
>>> for item in cycle(prices.items()):
... if not total_items:
... break
... total_items -= 1
... print(item)
...
('apple', 0.4)
('orange', 0.35)
('banana', 0.25)
('apple', 0.4)
('orange', 0.35)
('banana', 0.25)
('apple', 0.4)
('orange', 0.35)
('banana', 0.25)
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%AD%D1%82%D0%BE%D1%82-%D0%BA%D0%BE%D0%B4-%D0%BF%D0%B5%D1%80%D0%B5%D0%B1%D0%B8%D1%80%D0%B0%D0%B5%D1%82-"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Этот код перебирает **prices** определенное количество раз (в данном случае 3). Этот цикл может длиться столько, сколько нужно, но вы должны позаботиться о его остановке. Условие **if** прерывает цикл, когда **total\_items** ведет обратный отсчет до нуля.</div></div></div></div></div>### Итерация с chain()

**itertools** также предоставляет функцию **chain(\*iterables)**, которая получает некоторые итерируемые аргументы в качестве аргументов и создает итератор, который возвращает элементы из итерируемого объекта до тех пор, пока он не будет исчерпан, а затем итерирует по следующему итерируемуго объекту и т. д., пока все они не будут исчерпаны.

Это позволяет вам перебирать несколько словарей в цепочке, как в случае с **collections.ChainMap**:

```python
>>> from itertools import chain
>>> fruit_prices = {'apple': 0.40, 'orange': 0.35, 'banana': 0.25}
>>> vegetable_prices = {'pepper': 0.20, 'onion': 0.55, 'tomato': 0.42}
>>> for item in chain(fruit_prices.items(), vegetable_prices.items()):
... print(item)
...
('apple', 0.4)
('orange', 0.35)
('banana', 0.25)
('pepper', 0.2)
('onion', 0.55)
('tomato', 0.42)
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%92-%D0%BF%D1%80%D0%B8%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%BD%D0%BE%D0%BC-%D0%B2%D1%8B%D1%88%D0%B5-%D0%BA"><div class="enlighter-code"><div class="enlighter"><div class=""><div>В приведенном выше коде **chain()** вернула итерацию, которая объединила элементы из **fruit\_prices** и **vegetable\_prices**.</div></div></div></div></div>Также возможно использовать **.keys()** или **.values()**, в зависимости от ваших потребностей, с условием быть однородным: если вы используете **.keys()** в качестве аргумента для **chain()**, то вам нужно использовать **.keys( )** для остальных из них.

## Использование оператора распаковки словаря (\*\*)

Python 3.5 приносит новую и интересную функцию. [PEP 448 – Additional Unpacking Generalizations](https://www.python.org/dev/peps/pep-0448) могут упростить вашу жизнь, когда дело доходит до перебора нескольких словарей в Python. Давайте посмотрим, как это работает, на коротком примере.

Предположим, у вас есть два (или более) словаря, и вам нужно выполнять их итерацию вместе, без использования **collection.ChainMap** или **itertools.chain()**. В этом случае можно использовать оператор распаковки словаря **(\*\*)**, чтобы объединить два словаря в новый и затем выполнить итерацию по нему:

```python
>>> fruit_prices = {'apple': 0.40, 'orange': 0.35}
>>> vegetable_prices = {'pepper': 0.20, 'onion': 0.55}
>>> # How to use the unpacking operator **
>>> {**vegetable_prices, **fruit_prices}
{'pepper': 0.2, 'onion': 0.55, 'apple': 0.4, 'orange': 0.35}
>>> # You can use this feature to iterate through multiple dictionaries
>>> for k, v in {**vegetable_prices, **fruit_prices}.items():
... print(k, '->', v)
...
pepper -> 0.2
onion -> 0.55
apple -> 0.4
orange -> 0.35
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-python enlighter-hover " id="bkmrk-%D0%9E%D0%BF%D0%B5%D1%80%D0%B0%D1%82%D0%BE%D1%80-%D1%80%D0%B0%D1%81%D0%BF%D0%B0%D0%BA%D0%BE%D0%B2%D0%BA%D0%B8-"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Оператор распаковки словаря **(\*\*)** действительно замечательная функция в Python. Она позволяет объединить несколько словарей в один новый, как мы это делали в примере с **vegetable\_prices** и **fruit\_prices**. После объединения словарей с оператором распаковки вы можете перебирать новый словарь как обычно.</div></div></div></div></div>Важно отметить, что если словари, которые вы пытаетесь объединить, имеют повторяющиеся или общие ключи, то значения самого послденего словаря будут преобладать:

```python
>>> vegetable_prices = {'pepper': 0.20, 'onion': 0.55}
>>> fruit_prices = {'apple': 0.40, 'orange': 0.35, 'pepper': .25}
>>> {**vegetable_prices, **fruit_prices}
{'pepper': 0.25, 'onion': 0.55, 'apple': 0.4, 'orange': 0.35}
```

<div class="enlighter-default enlighter-v-standard enlighter-t-enlighter enlighter-l-generic enlighter-hover " id="bkmrk-%D0%9A%D0%BB%D1%8E%D1%87-pepper-%D0%BF%D1%80%D0%B8%D1%81%D1%83%D1%82%D1%81%D1%82"><div class="enlighter-code"><div class="enlighter"><div class=""><div>Ключ **pepper** присутствует в обоих словарях. После объединения их значение **fruit\_prices** для **pepper** (0.25) превалирует, потому что **fruit\_prices** – самый последний словарь.</div></div></div></div></div>## Заключение

В этой статье мы основы того, как перебирать словарь в Python, а также некоторые более продвинутые методы и стратегии!

**Вы узнали:**

- Что такое словари, а также некоторые их основные функции и детали реализации
- Каковы основные способы перебора словаря в Python:
- Какие задачи вы можете выполнить, итерируя словарь
- Как использовать некоторые более сложные методы и стратегии для перебора словаря