You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

621 lines
18 KiB
Plaintext

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

{
"cells": [
{
"cell_type": "markdown",
"id": "35e7641e",
"metadata": {},
"source": [
"# Словари #"
]
},
{
"cell_type": "markdown",
"id": "aa115439",
"metadata": {},
"source": [
"На этой лекции мы поговорим про словари.\n",
"\n",
"Словари являются важнейшей структурой данных в Python'е и они позволяют хранить данные в формате ключ-значение.\n",
"\n",
"Чтобы определить словарь, нужно использовать литерал фигурные скобки или просто вызвать `dict`."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "647047ab",
"metadata": {},
"outputs": [],
"source": [
"empty_dict = {}\n",
"empty_dict = dict()"
]
},
{
"cell_type": "markdown",
"id": "b793bf48",
"metadata": {},
"source": [
"Если мы хотим определить словарь, в котором уже есть какие-то данные, мы просто пишем наши ключ-значение через двоеточие. Например, словарь collections_map содержит отображение и строк, и списки в листы."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "ab12602e",
"metadata": {},
"outputs": [],
"source": [
"collections_map = {\n",
" \"mutable\": [\"list\", \"set\", \"dict\"],\n",
" \"immutable\": [\"tuple\", \"frozenset\"]\n",
"}"
]
},
{
"cell_type": "markdown",
"id": "8f0a511f",
"metadata": {},
"source": [
"Чем хороши словари? Они позволяют получить значение по ключу за константное время, очень быстро. Это достигается с помощью алгоритма хеширования. Например, мы можем получить `immutable` лист."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "ce41b9bf",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['tuple', 'frozenset']\n"
]
}
],
"source": [
"print(collections_map[\"immutable\"])"
]
},
{
"cell_type": "markdown",
"id": "46286967",
"metadata": {},
"source": [
"Если мы попытаемся получить доступ по ключу, которого не существует, у нас Python выдаст нам ошибку KeyError, потому что такого ключа очевидно нет."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "bfbe0151",
"metadata": {},
"outputs": [
{
"ename": "KeyError",
"evalue": "'irresistible'",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m<ipython-input-4-c3adb9d5d5cd>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcollections_map\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m\"irresistible\"\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[1;31mKeyError\u001b[0m: 'irresistible'"
]
}
],
"source": [
"print(collections_map[\"irresistible\"])"
]
},
{
"cell_type": "markdown",
"id": "f9f60bb7",
"metadata": {},
"source": [
"Однако, часто бывает полезно попробовать взять значение по ключу и в случае неудачи вернуть какое-то дефолтное значение. Для этого есть встроенный метод `get` у словаря, который делает именно это. Например, мы попытались взять ключи `irresistible` и вернули `not found`."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "975284c8",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"not found\n"
]
}
],
"source": [
"print(collections_map.get(\"irresistible\", \"not found\"))"
]
},
{
"cell_type": "markdown",
"id": "ead7601e",
"metadata": {},
"source": [
"Чтобы проверить, содержится ли ключ в словаре, мы используем уже знакомые вам операторы."
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "faa26fae",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"\"mutable\" in collections_map"
]
},
{
"cell_type": "markdown",
"id": "b3a915d7",
"metadata": {},
"source": [
"Так как словарь является изменяемой структурой данных, мы можем добавлять и удалять элементы из него. Например, мы можем определить словарь `beatles_map`, который содержит знаменитых музыкантов и их инструменты, и добавить в него Ринго с ударными, просто используя доступ по ключу."
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "0f6226ae",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{'Paul': 'Bass', 'John': 'Guitar', 'George': 'Guitar'}\n"
]
}
],
"source": [
"beatles_map = {\n",
" \"Paul\": \"Bass\",\n",
" \"John\": \"Guitar\",\n",
" \"George\": \"Guitar\",\n",
"}\n",
"\n",
"print(beatles_map)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "0a54daf3",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{'Paul': 'Bass', 'John': 'Guitar', 'George': 'Guitar', 'Ringo': 'Drums'}\n"
]
}
],
"source": [
"beatles_map[\"Ringo\"] = \"Drums\"\n",
"\n",
"print(beatles_map)"
]
},
{
"cell_type": "markdown",
"id": "6d010fb3",
"metadata": {},
"source": [
"Чтобы удалить ключ и значение из словаря, можно использовать уже знакомый вам оператор del, который удаляет в данном случае Джона из нашего словаря."
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "230b9d49",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{'Paul': 'Bass', 'George': 'Guitar', 'Ringo': 'Drums'}\n"
]
}
],
"source": [
"del beatles_map[\"John\"]\n",
"\n",
"print(beatles_map)"
]
},
{
"cell_type": "markdown",
"id": "5d2a6238",
"metadata": {},
"source": [
"Также, чтобы добавить какой-то ключ-значение в словарь, можно использовать встроенный метод `update`, который принимает словарь и апдейтит существующий словарь."
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "d2ca1637",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{'Paul': 'Bass', 'George': 'Guitar', 'Ringo': 'Drums', 'John': 'Guitar'}\n"
]
}
],
"source": [
"beatles_map.update({\n",
" \"John\": \"Guitar\"\n",
"})\n",
"\n",
"print(beatles_map)"
]
},
{
"cell_type": "markdown",
"id": "ffbbe1b1",
"metadata": {},
"source": [
"Чтобы удалить ключ-значение из словаря и вернуть значение, можно использовать метод pop, и в данном случае мы удаляем Ринго, и нам возвращаются его ударные."
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "c68f6183",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Drums\n",
"{'Paul': 'Bass', 'George': 'Guitar', 'John': 'Guitar'}\n"
]
}
],
"source": [
"print(beatles_map.pop(\"Ringo\"))\n",
"\n",
"print(beatles_map)"
]
},
{
"cell_type": "markdown",
"id": "64580aff",
"metadata": {},
"source": [
"Часто бывает необходимо не только попробовать проверить, существует ли ключ в словаре, но и в случае неудачи добавить эту новую пару ключ-значение. Для этого есть метод `setdefault`, и давайте посмотрим, как он работает. Мы объявляем `unknown_dict`, который абсолютно пуст, и используя метод `setdefault` пытаемся взять какой-то ключ `key` и в случае неудачи добавим туда `default`."
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "403cdacb",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"default\n"
]
}
],
"source": [
"unknown_dict = {}\n",
"\n",
"print(unknown_dict.setdefault(\"key\", \"default\"))"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "f8dbee49",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'key': 'default'}"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"unknown_dict"
]
},
{
"cell_type": "markdown",
"id": "8fc6bb60",
"metadata": {},
"source": [
"Происходит именно это, у нас в нашем пустом словаре получилось отображение `key`, `default` и `default` вернулся к нам в результате вызова метода `setdefault`.\n",
"\n",
"Если мы попытаемся вызвать `setdefault` и в качестве дефолтного значения передаём `new_default`, у нас вернётся значение, которое уже лежит в словаре, значение `default`."
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "9b0fa584",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"default\n"
]
}
],
"source": [
"print(unknown_dict.setdefault(\"key\", \"new_default\"))"
]
},
{
"cell_type": "markdown",
"id": "3c5cf8c7",
"metadata": {},
"source": [
"Словари, как и все коллекции, поддерживают протокол итерации, поэтому мы можем итерироваться по словарю, например, с помощью метода `for`."
]
},
{
"cell_type": "code",
"execution_count": 23,
"id": "5acefef3",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{'mutable': ['list', 'set', 'dict'], 'immutable': ['tuple', 'frozenset']}\n"
]
}
],
"source": [
"print(collections_map)"
]
},
{
"cell_type": "code",
"execution_count": 22,
"id": "b4c7bb66",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"mutable\n",
"immutable\n"
]
}
],
"source": [
"for key in collections_map:\n",
" print(key)"
]
},
{
"cell_type": "markdown",
"id": "74c5246c",
"metadata": {},
"source": [
"Обратите внимание, мы итерируемся по ключам словаря. Можем вывести собственно ключи, которые содержатся в нашем словаре. \n",
"\n",
"Если нам нужно итерироваться не по ключам, как по умолчанию, а по ключам и значениям сразу можно использовать метод словаря `items`, который возвращает ключи и значения. Например, можно выводить в нашем `collections_map` как ключи, так и значения."
]
},
{
"cell_type": "code",
"execution_count": 24,
"id": "342baa0c",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"mutable: ['list', 'set', 'dict']\n",
"immutable: ['tuple', 'frozenset']\n"
]
}
],
"source": [
"for key, value in collections_map.items():\n",
" print(f\"{key}: {value}\")"
]
},
{
"cell_type": "markdown",
"id": "87b8d55f",
"metadata": {},
"source": [
"Если нужно итерироваться по значениям, используйте логично метод `values`, который возвращает именно значения. Также существует симметричный метод `keys`, который возвращает оператор ключей."
]
},
{
"cell_type": "code",
"execution_count": 25,
"id": "56344c1b",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['list', 'set', 'dict']\n",
"['tuple', 'frozenset']\n"
]
}
],
"source": [
"for value in collections_map.values():\n",
" print(value)"
]
},
{
"cell_type": "code",
"execution_count": 26,
"id": "3299f648",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"mutable\n",
"immutable\n"
]
}
],
"source": [
"for key in collections_map.keys():\n",
" print(key)"
]
},
{
"cell_type": "markdown",
"id": "d96b364e",
"metadata": {},
"source": [
"Важная особенность словарей в Python'е - они содержат ключи и значения в неупорядоченном виде, то есть вы не можете гарантировать, что ключи, например, отсортированы, или хранятся в том порядке, в каком вы их туда добавили. Однако, в Python'е существует `OrderedDict`, это тип, который содержится в модуле `collections`, который гарантирует вам, что ключи содержатся именно в том порядке, в каком вы их добавили в словарь. Например, мы можем вывести пару, число и строка, именно в том порядке, в каком мы их туда добавили."
]
},
{
"cell_type": "code",
"execution_count": 32,
"id": "b7ce5f64",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0\n",
"1\n",
"2\n",
"3\n",
"4\n",
"5\n",
"6\n",
"7\n",
"8\n",
"9\n"
]
}
],
"source": [
"from collections import OrderedDict\n",
"\n",
"ordered = OrderedDict()\n",
"\n",
"for number in range(10):\n",
" ordered[number] = str(number)\n",
" \n",
"for key in ordered:\n",
" print(key)"
]
},
{
"cell_type": "markdown",
"id": "8e4e659e",
"metadata": {},
"source": [
"По секрету с версии Python 3.8 порядок гарантирован."
]
},
{
"cell_type": "code",
"execution_count": 33,
"id": "b885b0f1",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0\n",
"1\n",
"2\n",
"3\n",
"4\n",
"5\n",
"6\n",
"7\n",
"8\n",
"9\n"
]
}
],
"source": [
"ordered = dict()\n",
"\n",
"for number in range(10):\n",
" ordered[number] = str(number)\n",
" \n",
"for key in ordered:\n",
" print(key)"
]
},
{
"cell_type": "markdown",
"id": "fb29decb",
"metadata": {},
"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.8.8"
}
},
"nbformat": 4,
"nbformat_minor": 5
}