{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "164f2285",
   "metadata": {},
   "source": [
    "# Списки и кортежи #"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a0860ec6",
   "metadata": {},
   "source": [
    "В этой лекции мы поговорим с вами о коллекциях.\n",
    "\n",
    "Коллекция - это переменная-контейнер, в которой может содержаться какое-то количество объектов, эти объекты могут быть одного типа или разного. В случае списков, о которых далее пойдет речь - это упорядоченные наборы элементов, которые могут быть разных типов. Собственно, списки определяются с помощью квадратных скобочек или с помощью вызова литерала `list`. Вы также можете создать список из одинаковых значений с помощью умножения."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "50d507c5",
   "metadata": {},
   "outputs": [],
   "source": [
    "empty_list = []\n",
    "empty_list = list()\n",
    "\n",
    "none_list = [None] * 10\n",
    "\n",
    "collections = [\"list\", \"tuple\", \"dict\", \"set\"]\n",
    "\n",
    "user_data = [\n",
    "    [\"Elena\", 4.4],\n",
    "    [\"Andrey\", 4.2]\n",
    "]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "826b2528",
   "metadata": {},
   "source": [
    "Чаще всего списки содержат переменные одного типа, например, строки. Однако бывает, что нужно добавлять в списки переменные разных типов. Это тоже возможно. Также списки могут содержать другие коллекции, как, например, `user_data`. Однако для таких данных чаще всего используются кортежи, о которых мы поговорим чуть позже."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1ca1cebf",
   "metadata": {},
   "source": [
    "Чтобы получить длину списка, можно вызвать встроенную функцию `len`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "71a1712b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(collections)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b8f1100d",
   "metadata": {},
   "source": [
    "И, как вы видите, для определения списка не нужно заранее знать длину списка, который вы создаете, списки изменяемые, и Python обо всем заботится о вас. Также интересно, что функция `len` выполняется за константное время, то есть не происходит `full scan`. Python делает все очень быстро."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "81b54f7f",
   "metadata": {},
   "source": [
    "Чтобы получить доступ к какому-то конкретному элементу списка, мы обращаемся по индексу к нему, также как и в строчках. Например, чтобы получить первый элемент, мы обращаемся по нулевому индексу, так как списки нумеруются с 0, а чтобы последний - к −1."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "4aaa7d90",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['list', 'tuple', 'dict', 'set']\n",
      "list\n",
      "set\n"
     ]
    }
   ],
   "source": [
    "print(collections)\n",
    "\n",
    "print(collections[0])\n",
    "print(collections[-1])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9314d073",
   "metadata": {},
   "source": [
    "Также индексы можно использовать для того, чтобы менять какие-то элементы внутри списка, например, мы можем заменить `set` на `frozenset`, обратившись к переменной по третьему индексу."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "58c77b64",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['list', 'tuple', 'dict', 'frozenset']\n"
     ]
    }
   ],
   "source": [
    "collections[3] = \"frozenset\"\n",
    "\n",
    "print(collections)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3c710948",
   "metadata": {},
   "source": [
    "Если мы обратимся по индексу, которого не существует, Python выдаст вам ошибку, скажет, что `list index out of range`, значит, что такого индекса еще нет. Опять же, ошибки в Python'е очень говорящие."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "0310e5b8",
   "metadata": {},
   "outputs": [
    {
     "ename": "IndexError",
     "evalue": "list index out of range",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mIndexError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-38-2668a2a12b12>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mcollections\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m10\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mIndexError\u001b[0m: list index out of range"
     ]
    }
   ],
   "source": [
    "collections[10]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e6986171",
   "metadata": {},
   "source": [
    "Читайте их, не бойтесь, они вам скажут, что именно произошло не так. Также можно проверить, существует ли конкретный объект в списке, с помощью оператора `in`. Например, у нас есть `tuple` в наших `collections`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "e7e3adfc",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\"tuple\" in collections"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "026bfc3a",
   "metadata": {},
   "source": [
    "Также списки поддерживают срезы так же, как и строки, работает все точно так же. Например, мы можем получить определенный набор элементов с помощью среза от первого до третьего."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "e4cf1f58",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n"
     ]
    }
   ],
   "source": [
    "range_list = list(range(10))\n",
    "print(range_list)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "43e860e6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 2]"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "range_list[1:3]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ab45e27a",
   "metadata": {},
   "source": [
    "Последний индекс не включается, будьте внимательны, и так как элементы в списках нумеруются с 0, у нас не включается 0 здесь. Мы можем опустить второй индекс и таким образом получить все элементы, начиная с третьего индекса, или, наоборот, до пятого индекса."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "6673dc75",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[3, 4, 5, 6, 7, 8, 9]"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "range_list[3:]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "66cf8cbb",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[0, 1, 2, 3, 4]"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "range_list[:5]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a107e276",
   "metadata": {},
   "source": [
    "Также мы можем опустить оба, и начальный и конечный индекс, и, например, скакать через один, получая только четные элементы списка."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "id": "342bac0e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n"
     ]
    }
   ],
   "source": [
    "print(range_list)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "id": "4b00d12e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[0, 2, 4, 6, 8]"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "range_list[::2]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "02cffa19",
   "metadata": {},
   "source": [
    "Мы можем также разворачивать список, обращаясь к −1 или делать более сложные операции, которые довольно редко встречаются, но важно представлять, что именно там происходит."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "c3722991",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "range_list[::-1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "ec0f88a5",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 3, 5, 7, 9]"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "range_list[1::2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "26023033",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[5, 4, 3, 2]"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "range_list[5:1:-1]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "da4080c4",
   "metadata": {},
   "source": [
    "Также важно знать, что при получении среза у вас создается новый объект, то есть получается новый список в этот момент."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "id": "5d0d323f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n",
      "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "print(range_list)\n",
    "print(range_list[:])\n",
    "\n",
    "range_list[:] is range_list"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "df2e16eb",
   "metadata": {},
   "source": [
    "Списки, как и все коллекции, поддерживают протокол итерации, значит, мы можем использовать цикл `for` для того, чтобы итерироваться по элементам списка."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5986024c",
   "metadata": {},
   "source": [
    "Обратите внимание, что итерации происходят именно по элементам списка, а не по индексам, как во многих языках.\n",
    "\n",
    "Например, мы можем итерироваться по нашим collections и выводить текущую коллекцию."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "id": "10d90a2a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Learning list...\n",
      "Learning tuple...\n",
      "Learning dict...\n",
      "Learning set...\n"
     ]
    }
   ],
   "source": [
    "collections = [\"list\", \"tuple\", \"dict\", \"set\"]\n",
    "\n",
    "for collection in collections:\n",
    "    print(f\"Learning {collection}...\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0e1999ee",
   "metadata": {},
   "source": [
    "Часто бывает нужно выводить не только элемент списка, а также его индекс. Для этого существует встроенная функция `enumerate`, которая возвращает индекс и текущий элемент.\n",
    "\n",
    "Например, мы можем вывести `collection` и соответствующий индекс."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "id": "2b746578",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0. list\n",
      "1. tuple\n",
      "2. dict\n",
      "3. set\n"
     ]
    }
   ],
   "source": [
    "for idx, collection in enumerate(collections):\n",
    "    print(f\"{idx}. {collection}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "41322654",
   "metadata": {},
   "source": [
    "Так как списки являются изменяемыми структурами данных, мы можем добавлять и удалять элементы.\n",
    "\n",
    "Для добавления элемента в список существует встроенный метод списка `append`, который добавляет переданную переменную в конец списка."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "id": "05b8d29e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['list', 'tuple', 'dict', 'set', 'OrderedDict']\n"
     ]
    }
   ],
   "source": [
    "collections.append(\"OrderedDict\")\n",
    "\n",
    "print(collections)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f9420aed",
   "metadata": {},
   "source": [
    "Например, мы можем добавить в наши `collections` `OrderedDict`.\n",
    "\n",
    "Если вам нужно расширить список каким-то другим списком, вы можете использовать метод `extend`, который добавляет переданный список в конец вашего списка."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "id": "fbf75b4e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['list', 'tuple', 'dict', 'set', 'OrderedDict', 'ponyset', 'unicorndict']\n"
     ]
    }
   ],
   "source": [
    "collections.extend([\"ponyset\", \"unicorndict\"])\n",
    "\n",
    "print(collections)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f0683229",
   "metadata": {},
   "source": [
    "Также можно использовать перегруженный оператор `+`, который делает логичную вещь, он добавляет переменную в конец, так же как `append` или `extend`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "id": "bedcf18e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['list', 'tuple', 'dict', 'set', 'OrderedDict', 'ponyset', 'unicorndict', None]\n"
     ]
    }
   ],
   "source": [
    "collections += [None]\n",
    "\n",
    "print(collections)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2059bc0b",
   "metadata": {},
   "source": [
    "Если вам нужно удалить какой-то элемент списка, можно использовать оператор `del` и указать индекс, который вы хотите удалить."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "53e26d94",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['list', 'tuple', 'dict', 'set', 'ponyset', 'unicorndict', None]\n"
     ]
    }
   ],
   "source": [
    "del collections[4]\n",
    "\n",
    "print(collections)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1b044d2f",
   "metadata": {},
   "source": [
    "Также существуют несколько полезных встроенных функций, которые помогут вам работать со списками, это `min`, `max` и `sum`. Они делают именно то, как называются, то есть, мы можем получить минимальный элемент, максимальный элемент или сумму элементов списка."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "id": "eaa5caa3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2\n",
      "19\n",
      "80\n"
     ]
    }
   ],
   "source": [
    "numbers = [4, 17, 19, 9, 2, 6, 10, 13]\n",
    "\n",
    "print(min(numbers))\n",
    "print(max(numbers))\n",
    "print(sum(numbers))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1e6bf2e7",
   "metadata": {},
   "source": [
    "Еще один полезный метод, который работает со списками и строками, это метод строки `join`.\n",
    "Он позволяет взять список и форматировать строку с помощью разделителя какого-то."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "id": "6abea50a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "python, perl, pascal\n"
     ]
    }
   ],
   "source": [
    "tag_list = [\"python\", \"perl\", \"pascal\"]\n",
    "print(\", \".join(tag_list))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3a8b4d4c",
   "metadata": {},
   "source": [
    "Еще одна часто встречающаяся операция со списками - это сортировка. В Python'е существует несколько методов сортировки, о которых мы сейчас с вами поговорим, а для начала создадим случайный список с помощью встроенного модуля `random`. Это модуль стандартной библиотеки, который вам не нужно дополнительно устанавливать. Создадим пустой список и в цикле добавим в него случайный элемент с помощью функции `append`, как вы видите."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "id": "5b839563",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[6, 14, 13, 16, 7, 4, 11, 9, 7, 16]\n"
     ]
    }
   ],
   "source": [
    "import random\n",
    "\n",
    "numbers = []\n",
    "\n",
    "for _ in range(10):\n",
    "    numbers.append(random.randint(1, 20))\n",
    "    \n",
    "print(numbers)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d4f11a29",
   "metadata": {},
   "source": [
    "Обратите внимание, что в цикле `for` используется для итерации нижнее подчеркивание, эта переменная говорит о том, что нам не важно, что именно присваивается при итерации.\n",
    "Таким образом, нам важно, что происходит итерация 10 раз, 10 раз присваивается новый элемент, а переменная сама нам не важна.\n",
    "\n",
    "У нас получился какой-то список, давайте попробуем его отсортировать.\n",
    "Для сортировки в Python'е существует встроенная функция `sorted`, которая возвращает отсортированный список. Все очень просто и логично."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "id": "0dfdf09a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[4, 6, 7, 7, 9, 11, 13, 14, 16, 16]\n",
      "[6, 14, 13, 16, 7, 4, 11, 9, 7, 16]\n"
     ]
    }
   ],
   "source": [
    "print(sorted(numbers))\n",
    "print(numbers)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5e8e66b9",
   "metadata": {},
   "source": [
    "Обратите внимание, что список возвращается именно новый, то есть старый список сохраняется неизменным. Если вам нужно изменить список, который вы имеете уже, можно использовать метод списка `sort`, который изменяет список `inplace`, сортирует его `inplace`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "id": "b00c7345",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[4, 6, 7, 7, 9, 11, 13, 14, 16, 16]\n"
     ]
    }
   ],
   "source": [
    "numbers.sort()\n",
    "print(numbers)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cd069246",
   "metadata": {},
   "source": [
    "Если вам нужно отсортировать список в обратном порядке, можно передать аргумент `reverse=True` в функцию sorted или в функцию sort метод списка."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "id": "e931b1dc",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[16, 16, 14, 13, 11, 9, 7, 7, 6, 4]\n"
     ]
    }
   ],
   "source": [
    "print(sorted(numbers, reverse=True))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "id": "97f2d225",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[16, 16, 14, 13, 11, 9, 7, 7, 6, 4]\n"
     ]
    }
   ],
   "source": [
    "numbers.sort(reverse=True)\n",
    "print(numbers)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b8dcc547",
   "metadata": {},
   "source": [
    "Также существует встроенная функция `reversed`, которая возвращает некий `reverse iterator`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "id": "d0b2693d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<list_reverseiterator object at 0x035A52E0>\n"
     ]
    }
   ],
   "source": [
    "print(reversed(numbers))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6713e790",
   "metadata": {},
   "source": [
    "Мы об итераторах поговорим позднее, пока важно понимать, что это просто объект, который поддерживает протокол итерации, и можно его преобразовать в список, а получится, в принципе, то же самое.\n",
    "\n",
    "Кроме методов, которые мы обсудили в этой лекции, существует также много других, о которых вы можете почитать в документации, например, метод `index` или `insert`."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "14e838d3",
   "metadata": {},
   "source": [
    "Собственно, в документации все про них подробно написано, не бойтесь это смотреть."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5e5ce574",
   "metadata": {},
   "source": [
    "А следующей структурой данных, о которой мы поговорим в этой лекции, являются кортежи.\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b93e3034",
   "metadata": {},
   "source": [
    "Кортежи, по сути, это неизменяемые списки, то есть это какой-то упорядоченный набор объектов, который мы не можем изменить - мы не можем ни добавлять, ни удалять элементы из него. \n",
    "\n",
    "Кортежи определяются с помощью круглых скобочек или литерала `tuple`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "id": "1caefad6",
   "metadata": {},
   "outputs": [],
   "source": [
    "empty_tuple = ()\n",
    "empty_tuple = tuple()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8e935365",
   "metadata": {},
   "source": [
    "Например, мы можем создать кортеж `immutables`, куда положим неизменяемые типы наши."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "id": "b431f577",
   "metadata": {},
   "outputs": [],
   "source": [
    "immutables = (int, str, tuple)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "de831021",
   "metadata": {},
   "source": [
    "Если мы попробуем в качестве нулевого элемента сделать `float`, у нас выведется ошибка, потому что кортежи неизменяемы."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "id": "3f059a2f",
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "'tuple' object does not support item assignment",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-66-36a3a527cff0>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mimmutables\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mfloat\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m: 'tuple' object does not support item assignment"
     ]
    }
   ],
   "source": [
    "immutables[0] = float"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b0b7177b",
   "metadata": {},
   "source": [
    "Однако будьте внимательны, несмотря на то что сами кортежи неизменяемые, объекты внутри них могут быть изменяемыми.\n",
    "\n",
    "Например, если у нас кортеж содержит список, мы можем добавлять элементы в этот список. Например, мы можем присоединить нолик."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "id": "7c5acc0a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "([0], [])\n"
     ]
    }
   ],
   "source": [
    "blink = ([], [])\n",
    "blink[0].append(0)\n",
    "\n",
    "print(blink)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f5f5d867",
   "metadata": {},
   "source": [
    "Также важная особенность кортежей — у них есть функция `hash`, к ним применяется функция `hash`, и поэтому они могут использоваться в качестве ключей в словарях, о которых мы поговорим чуть позднее."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "id": "1e0e50e1",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "750394483"
      ]
     },
     "execution_count": 69,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "hash(tuple())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eaaab34b",
   "metadata": {},
   "source": [
    "Будьте внимательней при определении кортежа из одного элемента, не забывайте писать запятую, потому что если вы забудете про нее, то Python сочтет вашу переменную типом `int`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "id": "ebb0c4e9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "int"
      ]
     },
     "execution_count": 70,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "one_element_tuple = (1,)\n",
    "guess_what = (1)\n",
    "\n",
    "type(guess_what)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1a57f366",
   "metadata": {},
   "source": [
    "Итак, на этой лекции мы с вами поговорили про списки.\n",
    "\n",
    "Списки — это упорядоченный и изменяемый набор объектов. Они поддерживают итерацию, вы можете применять к ним срезы или обращаться к элементам по индексам. Также в них довольно много встроенных методов и каких-то функций, которые вы можете использовать вместе со списками.\n",
    "\n",
    "Также мы разобрали кортежи.\n",
    "Кортежи — это неизменяемая версия списков, и кортежи могут использоваться в качестве ключей в словарях.\n",
    "\n",
    "На следующей лекции мы посмотрим с вами на задачу на изученный материал."
   ]
  }
 ],
 "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
}
