{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Конструкции управления потоком #"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Когда вы пишете программу, у вас постоянно возникает необходимость выполнить то или иное действие, тот или иной блок кода в зависимости от выполнения условия. Также может возникнуть необходимость какой-то блок кода выполнить несколько раз. Для этого существуют конструкции управления потоком. Об этих конструкциях мы и будем говорить в этой лекции."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Первое, на что мы посмотрим — это оператор `if`. Оператор `if` используется для выполнения каких-то действий при выполнении условия. Давайте посмотрим на пример."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Условие выполнено!\n"
     ]
    }
   ],
   "source": [
    "company = \"vniitf.ru\"\n",
    "\n",
    "if \"vniitf\" in company:\n",
    "    print(\"Условие выполнено!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "В данном примере мы определяем переменную `company` со значением `vniitf.ru` и далее используем оператор `if` и проверяем наличие подстроки `vniitf` в нашей строке. Если условие выполняется, а условие выполняется в том случае, если оно интерпретируется как `True`, то блок кода под `if` выполняется. В данном случае подстрока `vniitf` есть в строке `vniitf.ru` и наше условие выполняется.\n",
    "\n",
    "Иногда может быть так, что условие у вас сложное. Никаких проблем, вы можете записывать сложные условия в блоке оператора `if`, то есть вы можете выполнять различные bool'евские выражения, разделенные `or`, `and` и так далее. На втором примере как раз это показано."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Условие выполнено!\n"
     ]
    }
   ],
   "source": [
    "company = \"chelaxe.ru\"\n",
    "\n",
    "if \"vniitf\" in company or company.endswith(\".ru\"):\n",
    "    print(\"Условие выполнено!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "В некоторых случаях нужно выполнить какие-либо действия, когда условие не выполняется. Для этого существует оператор `else`. Оператор `else` в блоке `if…else` позволяет выполнить какой-то код, если условие не выполнилось. Посмотрим на примере."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "company = \"google.com\"\n",
    "\n",
    "if \"vniitf\" in company:\n",
    "    print(\"Условие выполнено!\")\n",
    "else:\n",
    "    print(\"Условие не выполнено!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "У нас в данном случае строка `google.com`, мы проверяем условие — наличие подстроки `vniitf` в строке `google.com` Оно, конечно же, не выполняется, но благодаря оператору `else` мы можем это отловить и выполнить код, который печатает нам на экран то, что условие не выполнено. Также есть возможность использовать выражение `if…elif…else`, в котором добавился оператор `elif`. Он используется тогда, когда нужно проверить друг за другом какие-то условия, не связанные друг с другом. Опять же на примере посмотрим."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Подстрока google найдена\n"
     ]
    }
   ],
   "source": [
    "company = \"google.com\"\n",
    "\n",
    "if \"vniitf\" in company:\n",
    "    print(\"Подстрока vniitf найдена\")\n",
    "elif \"google\" in company:\n",
    "    print(\"Подстрока google найдена\")\n",
    "else:\n",
    "    print(\"Подстрока не найдена\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Мы определяем переменную со значением `google.com` как строковый, и дальше у нас в данном случае срабатывает блок `elif`, который выполняется тогда, когда подстрока `google` была найдена в нашей строке.\n",
    "\n",
    "Также во многих языках программирования вы могли встречать тернарный оператор. В Python'е есть его аналог, и он записывается вот таким вот образом, который вы видите на примере."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Argentina\n"
     ]
    }
   ],
   "source": [
    "score_1 = 5\n",
    "score_2 = 0\n",
    "\n",
    "winner = \"Argentina\" if score_1 > score_2 else \"Jamaica\"\n",
    "\n",
    "print(winner)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "То есть переменной будет присвоена строка `Argentina` в том случае, если условие выполнено, иначе будет присвоена строка `Jamaica`. Все это записывается в одну строчку, как вы можете видеть. В некоторых случаях это удобно.\n",
    "\n",
    "Перейдем к другому оператору, оператору `while`. `While` позволяет выполнять блок до тех пор, пока выполняется какое-то условие. Опять же давайте посмотрим на пример."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "100\n"
     ]
    }
   ],
   "source": [
    "i = 0\n",
    "while i < 100:\n",
    "    i += 1\n",
    "    \n",
    "print(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Мы определяем переменную, `i = 0`, и будем прибавлять к переменной `i` единичку до тех пор, пока она меньше 100. Достаточно всё просто, мы пишем `while i < 100`, прибавляем единичку."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "i = 3\n",
    "\n",
    "while i >= 0:\n",
    "    i -= 1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Сколько раз выполнится блок кода внутри цикла while?\n",
    "\n",
    "Дальше.\n",
    "\n",
    "Иногда вам нужно проитерироваться по какой-то последовательности. Для этого в Python существует выражение `for…in`. Мы на данный момент знаем две последовательности, о которых уже рассказывали — это строка и это байтовая строка В примере на слайде мы итерируемся по строке. Строка содержит значение Alex, и мы итерируемся с помощью выражения `for…in`, `for letter in name`, мы принтим буковку. Каждый юникодный символ друг за другом попадает в тело нашего for-цикла и с помощью функции `print` попадает в дальнейшем на экран."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A\n",
      "l\n",
      "e\n",
      "x\n"
     ]
    }
   ],
   "source": [
    "name = \"Alex\"\n",
    "\n",
    "for letter in name:\n",
    "    print(letter)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Встроенный объект `range` позволяет итерироваться по целым числам. Что это значит? Если мы напишем `for i in range(3)`, то в теле блока `for` мы сначала получим ноль, потом один, потом два, но не три. Когда мы определяем объект `range`, он не включает в себя последнее значение."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "1\n",
      "2\n"
     ]
    }
   ],
   "source": [
    "for i in range(3):\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Давайте посмотрим на чуть более сложный пример."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "5050\n"
     ]
    }
   ],
   "source": [
    "result = 0\n",
    "\n",
    "for i in range(101):\n",
    "    result += i\n",
    "\n",
    "print(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Это задачка. Может быть, многие слышали историю про Фридриха Гаусса, который решил ее на уроке школьной математики очень быстро. Уверен, что на Python'е мы решим ее не менее быстро и суть ее в том, чтобы получить сумму чисел от 0 до 100. С помощью цикла `for` мы очень просто можем это сделать.\n",
    "\n",
    "Объект `range` также может инициализироваться с двумя аргументами, для того чтобы проитерироваться по последовательности чисел, начиная с какого-то числа и заканчивая каким-то числом. Но опять же последнее число не будет включено в последовательность."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "5\n",
      "6\n",
      "7\n"
     ]
    }
   ],
   "source": [
    "for i in range(5, 8):\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Также есть возможность проинициализировать `range` с тремя аргументами, и последним аргументом будет шаг. В данном случае это проще всего понять на примере. Мы итерируемся по числам от одного до десяти с шагом два, и на экран выводятся только нечетные числа, потому что мы перескакиваем по два."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "3\n",
      "5\n",
      "7\n",
      "9\n"
     ]
    }
   ],
   "source": [
    "for i in range(1, 10, 2):\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Также есть возможность итерироваться по числам в обратном порядке. Для этого в качестве шага объекту range нужно передать −1. На примере видно, что мы от десяти до пяти, опять же пять не включительно, в обратном порядке прогулялись."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10\n",
      "9\n",
      "8\n",
      "7\n",
      "6\n"
     ]
    }
   ],
   "source": [
    "for i in range(10, 5, -1):\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Перейдем к оператору `pass`. Оператор `pass` — это оператор, определяющий пустой блок, который ничего не делает. В основном на практике вы будете использовать этот оператор в качестве заглушки на время, пока вам не нужно писать код в каком-то блоке, но потом вы к нему вернетесь и замените оператор `pass` на что-то более полезное. Однако иногда для создания простых классов-наследников оператор `pass` может играть и полезную роль. Об этом вам ещё будет рассказываться в следующих лекциях. На примере мы можем посмотреть, `for i in range(100)`, `pass`, то есть мы итерируемся по числам и не делаем ничего в блоке цикла."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [],
   "source": [
    "for i in range(100):\n",
    "    pass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Следующий оператор, на который мы посмотрим — это оператор `break`. Оператор `break` позволяет выйти из цикла досрочно. Что это значит? Давайте посмотрим на простом примере.\n",
    "\n",
    "У нас есть цикл `while True`, это бесконечный цикл, потому что условие всегда `True`, и он работал бы бесконечно, потребляя ресурсы процессора, если бы не наш оператор `break`, который мы вставили в код. Он отработает тогда, когда переменная `result` становится больше 100. Это позволяет выйти из цикла `while`, и выполнение программы достигает выражения `print(result)` и мы видим результат выполнения. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "100\n"
     ]
    }
   ],
   "source": [
    "result = 0\n",
    "\n",
    "while True:\n",
    "    result += 1\n",
    "    if result >= 100:\n",
    "        break\n",
    "\n",
    "print(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Оператор `break` также работает и в циклах `for`, то есть если мы используем `break` внутри `for`, мы выходим из `for`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "1\n",
      "2\n",
      "3\n",
      "4\n"
     ]
    }
   ],
   "source": [
    "for i in range(10):\n",
    "    if i == 5:\n",
    "        break\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Также давайте посмотрим на оператор `continue`. Оператор `continue` позволяет перейти к следующей итерации в блоке цикла, не выполняя оставшиеся инструкции. Что это значит? Например, у нас есть задача сложить все числа от нуля до девяти, и при этом сложить только четные числа. С помощью `continue` мы можем реализовать это вот так, как вы видите на примере, то есть тогда, когда переменная `i` является нечетным числом, мы пишем `continue` и переходим к следующей итерации цикла `for`. Тем самым в `result` суммируются только четные числа, и мы получаем правильный ответ."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "20\n"
     ]
    }
   ],
   "source": [
    "result = 0\n",
    "\n",
    "for i in range(10):\n",
    "    if i % 2 != 0:\n",
    "        continue\n",
    "    result += i\n",
    "\n",
    "print(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Выберите варианты, в которых цикл будет работать бесконечно:\n",
    "\n",
    "- [x] Вариант первый:\n",
    "\n",
    "```python\n",
    "while True:\n",
    "  continue\n",
    "```\n",
    "\n",
    "- [x] Вариант второй:\n",
    "\n",
    "```python\n",
    "while True:\n",
    "  pass\n",
    "```\n",
    "\n",
    "- [ ] Вариант третий:\n",
    "\n",
    "```python\n",
    "while True:\n",
    "  break\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Так же для `for` и `while` есть `else` который срабатывает по окончанию, но не сработает если был использован `break`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "while\n",
      "else\n"
     ]
    }
   ],
   "source": [
    "flag = True\n",
    "\n",
    "while flag:\n",
    "    print(\"while\")\n",
    "    flag = False\n",
    "        \n",
    "else:\n",
    "    print(\"else\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "while\n"
     ]
    }
   ],
   "source": [
    "flag = True\n",
    "\n",
    "while flag:\n",
    "    print(\"while\")\n",
    "    break\n",
    "        \n",
    "else:\n",
    "    print(\"else\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "for\n",
      "else\n"
     ]
    }
   ],
   "source": [
    "for i in range(1):\n",
    "    print(\"for\")\n",
    "    \n",
    "else:\n",
    "    print(\"else\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "for\n"
     ]
    }
   ],
   "source": [
    "for i in range(1):\n",
    "    print(\"for\")\n",
    "    break\n",
    "    \n",
    "else:\n",
    "    print(\"else\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Теперь, когда мы рассмотрели все основные конструкции управления потоком, мы можем попробовать применить их на практике и написать небольшую программу, которая будет содержать их в себе. Давайте это сделаем.\n",
    "\n",
    "[Далее...](Пример%20на%20управление%20потоком.ipynb)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.10.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
