{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Словари" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Простой словарь" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Возьмем игру с инопланетными пришельцами, которые имеют разные цвета и приносят разное количество очков игроку. В следующем простом словаре хранится информация об одном конкретном пришельце:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "green\n", "5\n" ] } ], "source": [ "alien_0 = {'color': 'green', 'points': 5}\n", "print(alien_0['color'])\n", "print(alien_0['points'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Работа со словарями" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Словарь в языке Python представляет собой совокупность пар «ключ—значение». Каждый ключ связывается с некоторым значением, и программа может получить значение, связанное с заданным ключом. Значением может быть число, строка, список и даже другой словарь. Собственно, любой объект, создаваемый в программе Python, может стать значением в словаре.\n", "В Python словарь заключается в фигурные скобки{}, в которых приводится последовательность пар *«ключ—значение»*, как в предыдущем примере:\n", "* alien_0 = {'color': 'green', 'points': 5}\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Обращение к значениям в словаре" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Чтобы получить значение, связанное с ключом, укажите имя словаря, а затем ключ в квадратных скобках:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "green\n" ] } ], "source": [ "alien_0 = {'color': 'green'}\n", "print(alien_0['color'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Добавление новых пар «ключ—значение»" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Словари относятся к динамическим структурам данных: в словарь можно в любой момент добавлять новые пары «ключ—значение». Для этого указывается имя словаря, за которым в квадратных скобках следует новый ключ с новым значением. Добавим в словарь alien_0 еще два атрибута: координаты *x* и *y* для вывода изображения пришельца в определенной позиции экрана. Допустим, пришелец должен отображаться у левого края экрана, в 25 пикселах от верхнего края. Так как система экранных координат обычно располагается в левом верхнем углу, для размещения пришельца у левого края координата *x* должна быть равна 0, а координата *y* — 25:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'color': 'green', 'points': 5}\n", "{'color': 'green', 'points': 5, 'x_position': 0, 'y_position': 25}\n" ] } ], "source": [ "alien_0 = {'color': 'green', 'points': 5}\n", "print(alien_0)\n", "alien_0['x_position'] = 0\n", "alien_0['y_position'] = 25\n", "print(alien_0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Создание пустого словаря" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "В некоторых ситуациях бывает удобно (или даже необходимо) начать с пустого словаря, а затем добавлять в него новые элементы. Чтобы начать заполнение пустого словаря, определите словарь сп устой парой фигурных скобок, а затем добавляйте новые пары «ключ—значение» (каждая пара вотдельной строке). Например, вот как строитсясловарь alien_0:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'color': 'green', 'points': 5}\n" ] } ], "source": [ "alien_0 = {}\n", "alien_0['color'] = 'green'\n", "alien_0['points'] = 5\n", "print(alien_0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Обычно пустые словари используются при хранении данных, введенных пользователем, или при написании кода, автоматически генерирующего большое количество пар «ключ—значение»." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Изменение значений всловаре" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Чтобы изменить значение в словаре, укажите имя словаря с ключом в квадратных скобках, а затем новое значение, которое должно быть связано с этим ключом. Допустим, в процессе игры цвет пришельца меняется с зеленого на желтый:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The alien is green.\n", "The alien is now yellow.\n" ] } ], "source": [ "alien_0 = {'color': 'green'}\n", "print(\"The alien is \" + alien_0['color'] + \".\")\n", "alien_0['color'] = 'yellow'\n", "print(\"The alien is now \" + alien_0['color'] + \".\")\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Рассмотрим более интересный пример: отслеживание позиции пришельца, который может двигаться с разной скоростью. Мы сохраним значение, представляющее текущую скорость пришельца, и используем его для определения величины горизонтального смещения:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Original x-position: 0\n", "New x-position: 2\n" ] } ], "source": [ "alien_0 = {'x_position': 0, 'y_position': 25, 'speed': 'medium'}\n", "print(\"Original x-position: \" + str(alien_0['x_position']))\n", "# Пришелец перемещается вправо.# Вычисляем величину смещения на основании текущей скорости.\n", "if alien_0['speed'] == 'slow':\n", " x_increment = 1\n", "elif alien_0['speed'] == 'medium':\n", " x_increment = 2\n", "else:\n", " # Пришелец двигается быстро.\n", " x_increment = 3# Новая позиция равна сумме старой позиции иприращения.\n", "alien_0['x_position'] = alien_0['x_position'] + x_increment\n", "print(\"New x-position: \" + str(alien_0['x_position']))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Удаление пар «ключ—значение»" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Когда информация, хранящаяся в словаре, перестает быть ненужной, пару «ключ—значение» можно полностью удалить при помощи команды *del*. При вызове достаточно передать имя словаря и удаляемый ключ. Например, в следующем примере из словаряa lien_0 удаляется ключ'points'вместе со значением:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'color': 'green', 'points': 5}\n", "{'color': 'green'}\n" ] } ], "source": [ "alien_0 = {'color': 'green', 'points': 5}\n", "print(alien_0)\n", "del alien_0['points']\n", "print(alien_0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Словарь с однотипными объектами" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "В предыдущем примере в словаре сохранялась разнообразная информация ободном объекте (пришельце из компьютерной игры). Словарь также может ис-пользоваться для хранения одного вида информации омногих объектах. Допустим,вы хотите провести опрос среди коллег иузнать их любимый язык программиро-вания. Результаты простого опроса удобно сохранить всловаре:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "favorite_languages = {\n", " 'jen': 'python',\n", " 'sarah': 'c',\n", " 'edward': 'ruby',\n", " 'phil': 'python',}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Пары в словаре в этой записи разбиты по строкам. Ключами являются имена участников опроса, а значениями — выбранные ими языки. Если вы знаете, что для определения словаря потребуется более одной строки, нажмите клавишу Enter после ввода открывающей фигурной скобки. Снабдите следующую строку отступом на один уровень (четыре пробела) и запишите первую пару «ключ—значение», по-ставив за ней запятую. После этого при нажатии Enter ваш текстовый редактор будет автоматически снабжать все последующие пары таким же отступом, как у первой.\n", "Завершив определение словаря, добавьте закрывающую фигурную скобку в новой строке после последней пары «ключ—значение» и снабдите ее отступом на одинуровень, чтобы она была выровнена по ключам. За последней парой также рекомендуется включить запятую, чтобы при необходимости все было готово к добавлению новой пары «ключ—значение» в следующей строке." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Перебор словаря" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Словарь Python может содержать как несколько пар «ключ—значение», так и миллионы таких пар. Поскольку в словаре может храниться большой объем данных, Python предоставляет средства для перебора элементов словаря. Информация может храниться в словарях по-разному, поэтому предусмотрены разные способы перебора. Программа может перебрать все пары «ключ—значение» в словаре, только ключи или только значения." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Перебор всех пар «ключ—значение»" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Key: username\n", "Value: efermi\n", "\n", "Key: first\n", "Value: enrico\n", "\n", "Key: last\n", "Value: fermi\n" ] } ], "source": [ "user_0 = {\n", " 'username': 'efermi',\n", " 'first': 'enrico',\n", " 'last': 'fermi',\n", "}\n", "for key, value in user_0.items():\n", " print(\"\\nKey: \" + key)\n", " print(\"Value: \" + value)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Jen's favorite language is Python.\n", "Sarah's favorite language is C.\n", "Edward's favorite language is Ruby.\n", "Phil's favorite language is Python.\n" ] } ], "source": [ "favorite_languages = {\n", " 'jen': 'python',\n", " 'sarah': 'c',\n", " 'edward': 'ruby','phil': 'python',\n", "}\n", "for name, language in favorite_languages.items():\n", " print(name.title() + \"'s favorite language is \" +language.title() + \".\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Перебор всех ключей всловаре" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Метод keys() удобен в тех случаях, когда вы не собираетесь работать со всеми значениями в словаре. Переберем словарь favorite_languages и выведем имена всех людей, участвовавших в опросе:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Jen\n", "Sarah\n", "Edward\n", "Phil\n" ] } ], "source": [ "favorite_languages = {\n", " 'jen': 'python',\n", " 'sarah': 'c',\n", " 'edward': 'ruby',\n", " 'phil': 'python',\n", "}\n", "for name in favorite_languages.keys():\n", " print(name.title())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Чтобы обратиться в цикле к значению, связанному с интересующим вас ключом, используйте текущий ключ. Для примера выведем для пары друзей сообщение о выбранном ими языке. Мы переберем имена в словаре, как это делалось ранее, но, когда имя совпадает с именем одного из друзей, программа будет выводить специальное сообщение об их любимом языке:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Jen\n", "Sarah\n", " Hi Sarah, I see your favorite language is C!\n", "Edward\n", "Phil\n", " Hi Phil, I see your favorite language is Python!\n" ] } ], "source": [ "favorite_languages = {\n", " 'jen': 'python',\n", " 'sarah': 'c',\n", " 'edward': 'ruby',\n", " 'phil': 'python',\n", "}\n", "friends = ['phil', 'sarah']\n", "for name in favorite_languages.keys():\n", " print(name.title())\n", " if name in friends:\n", " print(\" Hi \" + name.title() +\", I see your favorite language is \" + favorite_languages[name].title() + \"!\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Метод *keys()* также может использоваться для проверки того, участвовал ли конкретный человек в опросе:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Erin, please take our poll!\n" ] } ], "source": [ "favorite_languages = {\n", " 'jen': 'python',\n", " 'sarah': 'c',\n", " 'edward': 'ruby',\n", " 'phil': 'python',}\n", "if 'erin' not in favorite_languages.keys():\n", " print(\"Erin, please take our poll!\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Упорядоченный перебор ключей словаря" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Словарь всегда поддерживает связь между ключом и связанным с ним значением,\n", "но порядок получения элементов из словаря непредсказуем. Впрочем, это не создает проблем, потому что обычно требуется лишь получить правильное значение,связанное с каждым ключом. Один из способов получения элементов вопределенном порядке основан на сортировке ключей, возвращаемых циклом for. Для получения упорядоченной копии ключей можно воспользоваться функцией *sorted()*:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Edward, thank you for taking the poll.\n", "Jen, thank you for taking the poll.\n", "Phil, thank you for taking the poll.\n", "Sarah, thank you for taking the poll.\n" ] } ], "source": [ "favorite_languages = {\n", " 'jen': 'python',\n", " 'sarah': 'c',\n", " 'edward': 'ruby',\n", " 'phil': 'python',\n", "}\n", "for name in sorted(favorite_languages.keys()):\n", " print(name.title() + \", thank you for taking the poll.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Перебор всех значений в словаре" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Если вас прежде всего интересуют значения, содержащиеся в словаре, используйте метод values() для получения списка значений без ключей. Допустим, вы хотите просто получить список всех языков, выбранных в опросе, и вас не интересуют имена людей, выбравших каждый язык:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The following languages have been mentioned:\n", "Python\n", "C\n", "Ruby\n", "Python\n" ] } ], "source": [ "favorite_languages = {\n", " 'jen': 'python',\n", " 'sarah': 'c',\n", " 'edward': 'ruby',\n", " 'phil': 'python',\n", "}\n", "print(\"The following languages have been mentioned:\")\n", "for language in favorite_languages.values():\n", " print(language.title())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Значения извлекаются из словаря без проверки на возможные повторения. Для небольших словарей это может быть приемлемо, но в опросах с большим количеством респондентов список будет содержать слишком много дубликатов. Чтобы получить список выбранных языков без повторений, можно воспользоваться множеством *(set)*." ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The following languages have been mentioned:\n", "Ruby\n", "Python\n", "C\n" ] } ], "source": [ "favorite_languages = {\n", " 'jen': 'python',\n", " 'sarah': 'c',\n", " 'edward': 'ruby',\n", " 'phil': 'python',\n", "}\n", "print(\"The following languages have been mentioned:\")\n", "for language in set(favorite_languages.values()):\n", " print(language.title())\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Вложение" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Иногда нужно сохранить множество словарей в списке или сохранить список как значение элемента словаря. Создание сложных структур такого роданазывается *вложением*. Вы можете вложить множество словарей в список,список элементов в словарь или даже словарь внутрь другого словаря. Как наглядно показывают следующие примеры, вложение — чрезвычайно мощный механизм." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Список словарей" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Словарьa lien_0 содержит разнообразную информацию об одном пришельце, но в нем нет места для хранения информации о втором пришельце, не говоря уже оцелом экране, забитом пришельцами. Как смоделировать флот вторжения? Например, можно создать список пришельцев, в котором каждый элемент представляет собой словарь с информацией о пришельце. Следующий код строит список из трех пришельцев:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'color': 'green', 'points': 5}\n", "{'color': 'yellow', 'points': 10}\n", "{'color': 'red', 'points': 15}\n" ] } ], "source": [ "alien_0 = {'color': 'green', 'points': 5}\n", "alien_1 = {'color': 'yellow', 'points': 10}\n", "alien_2 = {'color': 'red', 'points': 15}\n", "aliens = [alien_0, alien_1, alien_2]\n", "for alien in aliens:\n", " print(alien)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Конечно, в реалистичном примере будут использоваться более трех пришельцев, которые будут генерироваться автоматически. В следующем примере функция *range()* создает флот из 30 пришельцев:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'color': 'green', 'points': 5, 'speed': 'slow'}\n", "{'color': 'green', 'points': 5, 'speed': 'slow'}\n", "{'color': 'green', 'points': 5, 'speed': 'slow'}\n", "{'color': 'green', 'points': 5, 'speed': 'slow'}\n", "{'color': 'green', 'points': 5, 'speed': 'slow'}\n", "...\n", "Total number of aliens: 30\n" ] } ], "source": [ "# Создание пустого списка для хранения пришельцев.\n", "aliens = []\n", "# Создание 30 зеленых пришельцев.\n", "for alien_number in range(30):\n", " new_alien = {\n", " 'color': 'green', \n", " 'points': 5, \n", " 'speed': 'slow'}\n", " aliens.append(new_alien)\n", "# Вывод первых 5 пришельцев:\n", "for alien in aliens[:5]:\n", " print(alien)\n", "print(\"...\")\n", "# Вывод количества созданных пришельцев.\n", "print(\"Total number of aliens: \" + str(len(aliens)))\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Все пришельцы обладают одинаковыми характеристиками, но Python рассматривает каждого пришельца как отдельный объект, что позволяет изменять атрибуты каждого владельца по отдельности. Как работать с таким множеством? Представьте, что в этой игре некоторые пришельцы изменяют цвет и начинают двигаться быстрее. Когда приходит время смены цветов, мы можем воспользоваться циклом for и командой if для изменения цвета. Например, чтобы превратить первых трех пришельцев в желтых, двигающихся со средней скоростью и приносящих игроку по 10 очков, можно действовать так:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'color': 'yellow', 'points': 10, 'speed': 'medium'}\n", "{'color': 'yellow', 'points': 10, 'speed': 'medium'}\n", "{'color': 'yellow', 'points': 10, 'speed': 'medium'}\n", "{'color': 'green', 'points': 5, 'speed': 'slow'}\n", "{'color': 'green', 'points': 5, 'speed': 'slow'}\n", "...\n" ] } ], "source": [ "# Создание пустого списка для хранения пришельцев.aliens = []\n", "# Создание 30 зеленых пришельцев.for alien_number in range (0,30):\n", "new_alien = {\n", " 'color': 'green', \n", " 'points': 5, \n", " 'speed': 'slow'}\n", "aliens.append(new_alien)\n", "for alien in aliens[0:3]:\n", " if alien['color'] == 'green':\n", " alien['color'] = 'yellow'\n", " alien['speed'] = 'medium'\n", " alien['points'] = 10\n", "# Вывод первых 5 пришельцев:\n", "for alien in aliens[0:5]:\n", " print(alien)\n", "print(\"...\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Чтобы изменить первых трех пришельцев, мы перебираем элементы среза, включающего только первых трех пришельцев. В данный момент все пришельцы зеленые('green'), но так будет не всегда, поэтому мы пишем команду if, которая гарантирует, что изменяться будут только зеленые пришельцы. Если пришелец зеленый,то его цвет меняется на желтый ('yellow'), скорость на среднюю ('medium'), а награда увеличивается до 10 очков." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Цикл можно расширить, добавив блок elif для превращения желтых пришельцев в красных— быстрых и приносящих игроку по 15 очков. Мы не станем приводить весь код, а цикл выглядит так:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for alien in aliens[0:3]:\n", " if alien['color'] == 'green':\n", " alien['color'] = 'yellow'\n", " alien['speed'] = 'medium'\n", " alien['points'] = 10\n", " elif alien['color'] == 'yellow':\n", " alien['color'] = 'red'\n", " alien['speed'] = 'fast'\n", " alien['points'] = 15" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Список в словаре" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.5" } }, "nbformat": 4, "nbformat_minor": 2 }