{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Объектно-ориентированное программирование и информационная безопасность\n",
    "\n",
    "*Валерий Семенов, Самарский университет*\n",
    "\n",
    "<div style=\"text-align:center\"><img src=\"Python.png\" width=\"200\"></div>\n",
    "\n",
    "\n",
    "<h2 style=\"text-align:center; margin-top:60px\">Области видимости переменных</h2>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify\">В программировании особое внимание уделяется концепции локальных и глобальных переменных, а также связанное с ними представление об областях видимости. </div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\"><strong>Глобальные переменные</strong> – это переменные, объявленные в программе <u>вне функции</u>. В Python глобальные переменные видны (то есть, - известны, доступны) в любой части модуля, включая функции. К ним можно обратиться по имени и получить связанное с ними значение. </div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify\"><strong>Локальные переменные</strong> – это переменные, объявленные <u>внутри функции</u>. Они видны только в локальной области видимости, которой является тело функции. </div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\">К локальной переменной нельзя обратиться из глобальной области видимости, потому что локальная переменная существует только в момент выполнения тела функции. При выходе из нее, локальные переменные исчезают. Компьютерная память, которая под них отводилась, освобождается. Когда функция будет снова вызвана, локальные переменные будут созданы заново. </div>\n",
    "\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify\">Таким образом, локальные переменные отлично подходят для временного хранения промежуточных результатов, необходимых только в пределах одной функции. </div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\">Рассмотрим следующий код: </div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "Введите номер фигуры (1-прямоугольник, 2-треугольник):  2\n",
      "Основание:  4\n",
      "Высота:  5\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Площадь: 10.00\n"
     ]
    }
   ],
   "source": [
    "def rectangle():   # Площадь прямоугольника\n",
    "    a = float(input(\"Ширина: \"))\n",
    "    b = float(input(\"Высота: \"))\n",
    "    print(\"Площадь: %.2f\" % (a * b))\n",
    "\n",
    "def triangle():   # Площадь треугольника\n",
    "    a = float(input(\"Основание: \"))\n",
    "    h = float(input(\"Высота: \"))\n",
    "    print(\"Площадь: %.2f\" % (0.5 * a * h))\n",
    "\n",
    "figure = input(\"Введите номер фигуры (1-прямоугольник, 2-треугольник): \")\n",
    "\n",
    "if figure == '1':\n",
    "    rectangle()\n",
    "elif figure == '2':\n",
    "    triangle()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<table style=\"border:groove; margin-top:20px; margin-left:80px; margin-right:80px\">\n",
    "    <tr>\n",
    "        <td style=\"background:LightCyan; height:60px\">\n",
    "            <div style=\"margin-left:30px; font-size:larger; line-height:26px\"><img alt=\"\" src=\"question.png\" style=\"float: left; margin-right:20px\" width=\"30\"; height=\"30\"><strong><i>Сколько здесь переменных?</i></strong> </div>\n",
    "            <div style=\"margin-left:80px; font-size:larger; line-height:26px\"><strong><i>Какие из них являются глобальными?</i></strong> </div>\n",
    "            <div style=\"margin-left:80px; font-size:larger; line-height:26px\"><strong><i>Какие переменные являются локальными?</i></strong>&nbsp;&nbsp;&nbsp;&nbsp; </div>\n",
    "        </td>\n",
    "    </tr>\n",
    "</table>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div style=\"text-indent:30px; text-align:justify\">Здесь пять переменных. </div>\n",
    "    \n",
    "<div style=\"text-indent:30px; text-align:justify\">Глобальной является только <strong>figure</strong>. </div>\n",
    "    \n",
    "<div style=\"text-indent:30px; text-align:justify\">Переменные <strong>a</strong> и <strong>b</strong> из функции <strong>rectangle</strong>, а также <strong>a</strong> и <strong>h</strong> из <strong>triangle</strong> – локальные. При этом локальные переменные с одним и тем же идентификатором <strong>a</strong>, но объявленные в разных функциях, – разные переменные. </div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\">Следует отметить, что идентификаторы <strong>rectangle</strong> и <strong>triangle</strong>, хотя и не являются именами переменных, а представляют собой имена функций, также имеют область видимости. В данном случае она глобальная, так как функции объявлены непосредственно в основной ветке программы. </div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify\">В приведенной программе к глобальной области видимости относятся заголовки объявлений функций, объявление и присваивание переменной <strong>figure</strong>, конструкция условного оператора. </div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify\">К локальной области относятся тела функций. Если, находясь в глобальной области видимости, мы попытаемся обратиться к локальной переменной, то возникнет ошибка: </div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "Ширина:  4\n",
      "Высота:  5\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Площадь: 20.00\n"
     ]
    },
    {
     "ename": "NameError",
     "evalue": "name 'a' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[2], line 3\u001b[0m\n\u001b[0;32m      1\u001b[0m rectangle()\n\u001b[1;32m----> 3\u001b[0m \u001b[38;5;28mprint\u001b[39m(a)\n",
      "\u001b[1;31mNameError\u001b[0m: name 'a' is not defined"
     ]
    }
   ],
   "source": [
    "rectangle()\n",
    "\n",
    "print(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div style=\"text-indent:30px; text-align:justify\">Однако мы можем обращаться из функций к глобальным переменным: </div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "Введите номер фигуры (1-прямоугольник, 2-треугольник):  1\n",
      "Ширина фигуры 1:  4\n",
      "Высота фигуры 1:  5\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Площадь: 20.00\n"
     ]
    }
   ],
   "source": [
    "def rectangle():   # Площадь прямоугольника\n",
    "    a = float(input(\"Ширина фигуры %s: \" % figure))\n",
    "    b = float(input(\"Высота фигуры %s: \" % figure))\n",
    "    print(\"Площадь: %.2f\" % (a * b))\n",
    "\n",
    "def triangle():   # Площадь треугольника\n",
    "    a = float(input(\"Основание фигуры %s: \" % figure))\n",
    "    h = float(input(\"Высота фигуры %s: \" % figure))\n",
    "    print(\"Площадь: %.2f\" % (0.5 * a * h))\n",
    "\n",
    "figure = input(\"Введите номер фигуры (1-прямоугольник, 2-треугольник): \")\n",
    "\n",
    "if figure == '1':\n",
    "    rectangle()\n",
    "elif figure == '2':\n",
    "    triangle()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div style=\"text-indent:30px; text-align:justify\">В данном случае из тел функций происходит обращение к имени <strong>figure</strong>, которое, из-за того, что было объявлено в глобальной области видимости, видимо во всей программе. </div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify\">Наши функции не совсем идеальны. Они должны вычислять площади фигур, но выводить результат на экран им не следовало бы. Вполне вероятна ситуация, когда результат нужен в программе для каких-то дальнейших вычислений, а выводить ли его на экран – вопрос второстепенный. </div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify\">Если функции не будут выводить, а только вычислять результат, то его надо где-то сохранить для дальнейшего использования. Для этого подошли бы глобальные переменные. В них можно записать результат. </div>\n",
    "    \n",
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\">Напишем программу вот так: </div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "Введите номер фигуры (1-прямоугольник, 2-треугольник):  2\n",
      "Основание:  4\n",
      "Высота:  5\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Площадь фигуры: 0.00\n"
     ]
    }
   ],
   "source": [
    "def rectangle():   # Площадь прямоугольника\n",
    "    a = float(input(\"Ширина: \"))\n",
    "    b = float(input(\"Высота: \"))\n",
    "    result = a * b\n",
    "\n",
    "def triangle():   # Площадь треугольника\n",
    "    a = float(input(\"Основание: \"))\n",
    "    h = float(input(\"Высота: \"))\n",
    "    result = 0.5 * a * h\n",
    "\n",
    "result = 0\n",
    "\n",
    "figure = input(\"Введите номер фигуры (1-прямоугольник, 2-треугольник): \")\n",
    "\n",
    "if figure == '1':\n",
    "    rectangle()\n",
    "elif figure == '2':\n",
    "    triangle()\n",
    "\n",
    "print(\"Площадь фигуры: %.2f\" % result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div style=\"text-indent:30px; text-align:justify\">Итак, мы ввели в программу глобальную переменную <strong>result</strong> и инициировали ее нулем. В функциях ей присваивается результат вычислений. В конце программы ее значение выводится на экран. Мы ожидаем, что программа будет прекрасно работать. </div>\n",
    "    \n",
    "<div style=\"text-indent:30px; text-align:justify\">Однако… что-то пошло не так. :-( </div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div style=\"text-indent:30px; text-align:justify\">Дело в том, что в Python присвоение значения переменной совмещено с ее объявлением (во многих других языках это не так).  </div>\n",
    "    \n",
    "<div style=\"text-indent:30px; text-align:justify\">Поэтому, когда имя <strong>result</strong> впервые упоминается в локальной области видимости, и при этом происходит присваивание ей значения, то создается локальная переменная <strong>result</strong>. Это другая переменная, никак не связанная с глобальной <strong>result</strong>. </div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify\">Когда функция завершает свою работу, то значение локальной <strong>result</strong> теряется, а глобальная не была изменена. </div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\">Когда мы вызывали внутри функции переменную <strong>figure</strong>, то ничего ей не присваивали. Наоборот, мы запрашивали ее значение. Интерпретатор Питона искал такую переменную сначала в локальной области видимости и не находил. После этого шел в глобальную и находил. </div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify\">В случае с <strong>result</strong> он ничего не ищет. Он выполняет вычисления справа от знака присваивания, создает локальную переменную <strong>result</strong>, связывает ее с полученным значением. </div>\n",
    "\n",
    "<table style=\"border:groove; margin-top:20px; margin-left:80px; margin-right:80px\">\n",
    "    <tr>\n",
    "        <td style=\"background:LightCyan; height:60px\">\n",
    "            <div style=\"margin-left:30px; font-size:larger; line-height:26px\"><img alt=\"\" src=\"nerd-face.png\" style=\"float: left; ; margin-right:20px\" width=\"30\"; height=\"30\">На самом деле можно принудительно обратиться к глобальной переменной. </br>Для этого существует команда <strong>global</strong>:</div>\n",
    "        </td>\n",
    "    </tr>\n",
    "</table>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "Введите номер фигуры (1-прямоугольник, 2-треугольник):  2\n",
      "Основание:  4\n",
      "Высота:  5\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Площадь фигуры: 10.00\n"
     ]
    }
   ],
   "source": [
    "def rectangle():   # Площадь прямоугольника\n",
    "    a = float(input(\"Ширина: \"))\n",
    "    b = float(input(\"Высота: \"))\n",
    "    global result\n",
    "    result = a * b\n",
    "\n",
    "def triangle():   # Площадь треугольника\n",
    "    a = float(input(\"Основание: \"))\n",
    "    h = float(input(\"Высота: \"))\n",
    "    global result\n",
    "    result = 0.5 * a * h\n",
    "\n",
    "result = 0\n",
    "\n",
    "figure = input(\"Введите номер фигуры (1-прямоугольник, 2-треугольник): \")\n",
    "\n",
    "if figure == '1':\n",
    "    rectangle()\n",
    "elif figure == '2':\n",
    "    triangle()\n",
    "\n",
    "print(\"Площадь фигуры: %.2f\" % result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div style=\"text-indent:30px; text-align:justify\">В таком варианте программа будет работать правильно. </div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\">Однако менять значения глобальных переменных в теле функции – плохая практика. В больших программах трудно отследить, где, какая функция и почему изменила их значение. Программист смотрит на исходное значение глобальной переменной и может подумать, что оно остается таким же. Сложно заметить, что какая-то функция поменяла его. Подобное может привести к логическим ошибкам. </div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\">Чтобы избавиться от необходимости использовать глобальные переменные, для функций существует возможность возврата результата своей работы в основную ветку программы. И уже это полученное из функции значение можно присвоить глобальной переменной в глобальной области видимости. То есть программист видит изменение значения переменной в основной ветке программы. Это делает программу более понятной. </div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h2 style=\"text-align:center; margin-top:30px; margin-bottom:30px\">Рекурсия</h2>\n",
    "\n",
    "<div style=\"text-align:center\"><img src=\"recursion.jpg\" width=\"500\"></div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\">В Python (как и в большинстве языков программирования) функция может вызывать другую функцию. </div>\n",
    "    \n",
    "<div style=\"text-indent:30px; text-align:justify\">Но функция также может вызывать саму себя. </div>\n",
    "    \n",
    "<table style=\"border:groove; margin-top:20px; margin-left:80px; margin-right:80px\">\n",
    "    <tr>\n",
    "        <td style=\"background:LightCyan; height:60px\">\n",
    "            <div style=\"margin-left:30px; font-size:larger; line-height:26px\"><img alt=\"\" src=\"nerd-face.png\" style=\"float: left; ; margin-right:20px\" width=\"30\"; height=\"30\"><strong>Рекурсия - это прием программирования, при которой функция вызывает саму себя.</strong></div>\n",
    "        </td>\n",
    "    </tr>\n",
    "</table>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div style=\"text-indent:30px; text-align:justify\">Рекурсия бывает полезна при выполнении некоторых задач в программировании. </div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\">Соответственно, рекурсивная функция — это такая функция, которая в процессе выполнения вызывает саму себя. </div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\">Рекурсивные функции состоят из двух частей: базового случая и рекурсивного случая. </div>\n",
    "    \n",
    "<div style=\"text-indent:30px; text-align:justify; margin-left:20px\"><strong>Базовый случай</strong> — это условие, при котором функция прекращает вызывать саму себя и возвращает результат. </div>\n",
    "    \n",
    "<div style=\"text-indent:30px; text-align:justify; margin-left:20px\"><strong>Рекурсивный случай</strong> — это условие, при котором функция вызывает саму себя для решения меньшей подзадачи. </div>\n",
    "\n",
    "<h3 style=\"text-align:center; margin-top:60px\">Вычисление факториала</h3>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\">Факториал числа <strong>n</strong> обозначается как <strong>n!</strong>. Это произведение всех натуральных чисел от <strong>1</strong> до <strong>n</strong>. </div>\n",
    "    \n",
    "<div style=\"text-indent:30px; text-align:justify\">Например, <strong>5! = 5 * 4 * 3 * 2 * 1 = 120</strong>. \n",
    "    \n",
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\">Факториал можно выразить через рекурсию следующим образом: </div> \n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify; margin-left:20px\"><strong>Базовый случай</strong> - если <strong>n</strong> равно <strong>1</strong>, то <strong>n! = 1</strong> </div>\n",
    "                                                                                                                                                 \n",
    "<div style=\"text-indent:30px; text-align:justify; margin-left:20px\"><strong>Рекурсивный случай</strong> - если <strong>n</strong> больше <strong>1</strong>, то <strong>n! = n * (n-1)!</strong> </div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\">Для решения такой задачи можно использовать два алгоритма - <strong>итерационный</strong> и <strong>рекурсивный</strong>. </div>\n",
    "\n",
    "<h4 style=\"text-align:center; margin-top:20px\"><u>Итерационный (или пошаговый) алгоритм</u></h4>\n",
    "    \n",
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\">Напишем цикл с количеством повторений, равным <strong>n</strong>, начиная с единицы, в котором на каждом шаге будем умножать номер шага на величину произведения <strong>factorial</strong>: </div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "120"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def factorial(n):  # Функция вычисления факториала\n",
    "    factorial = 1\n",
    "    for i in range(1, n+1):\n",
    "        factorial *= i\n",
    "    return factorial\n",
    "\n",
    "factorial(5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div style=\"text-indent:30px; text-align:justify\">Результат можно проверить <a href=\"https://allcalc.ru/node/213\"><strong>здесь</strong></a>.</div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h4 style=\"text-align:center; margin-top:60px\"><u>Рекурсивный алгоритм</u></h4>\n",
    "\n",
    "<div style=\"text-align:center; margin-top:40px\"><img src=\"recursion.png\" width=\"500\"></div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "120"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def factorial(n):  # Функция вычисления факториала\n",
    "    if n == 1:\n",
    "        return 1   # Базовое решение\n",
    "    else:\n",
    "        return n * factorial(n-1)  # Рекурсивный вызов\n",
    "\n",
    "factorial(5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div style=\"text-align:center\"><img src=\"matreshki.png\" width=\"900\"></div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h4 style=\"text-align:center; margin-top:20px\"><u>Преимущества рекурсии</u></h4>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\">Рекурсивный подход многим нравится, потому что он изящный и емкий, а описать такой алгоритм часто быстрее, чем аналоги. Вот основные преимущества создания рекуррентных решений. </div>\n",
    "<div style=\"text-indent:30px; text-align:justify\"><strong>Ясность</strong>. Прочитать рекурсивный код обычно проще, чем программу, полную ухищрений для решения той же задачи без рекурсии. Это важный плюс, если речь идет о коммерческом программировании, где код часто смотрят другие люди. </div>\n",
    "<div style=\"text-indent:30px; text-align:justify\"><strong>Наглядность</strong>. Некоторые задачи, вроде тех же чисел Фибоначчи или факториалов, — рекурсивные по самому своему определению. То же самое касается задач на ряды, фракталы и так далее. Решить такую задачу через рекурсию — один из наиболее наглядных и интуитивно понятных способов. Более того: люди пользуются рекурсией все время, даже просто когда разговаривают, и это лишний раз работает на интуитивное ее понимание. </div>\n",
    "<div style=\"text-indent:30px; text-align:justify\"><strong>Краткость</strong>. Рекурсивная функция обычно короче, чем реализация без рекурсии. Разработчику проще и удобнее написать несколько строк кода, чем создавать огромную программу, тратить время и силы и путаться в написанном. </div>\n",
    "<div style=\"text-indent:30px; text-align:justify\"><strong>Красота</strong>. Наконец, сам концепт многие считают красивым и изящным. Это и правда так — посмотрите на фракталы и снежинки: в них есть определенная красота. Рекурсию используют даже в искусстве: от матрешек до сложных узоров, украшающих готические соборы. </div>\n",
    "\n",
    "<h4 style=\"text-align:center; margin-top:20px\"><u>Недостатки рекурсии</u></h4>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\">Недостатков у рекурсивного подхода два, но они критичные и серьезно ограничивают применение этой концепции даже там, где она напрашивается.\n",
    "<div style=\"text-indent:30px; text-align:justify\"><strong>Риск переполнения</strong>. При всем перечисленном программисты пользуются рекурсией довольно осторожно. Она устроена так, что, пока не выполнится последний вызов функции, все предыдущие не завершатся — ведь они как бы «вкладывают» в себя последующие. Поэтому такие программы отнимают много ресурсов компьютера. Так что разработчики смотрят и на параметр производительности и решают, что выгоднее в конкретном случае — использовать рекурсию или нет. </div>\n",
    "<div style=\"text-indent:30px; text-align:justify\"><strong>Риск бесконечности</strong>. Если что-то пошло не так и программист случайно получил бесконечную рекурсию, единственный выход — принудительно закрыть программу. А потом переписать ее, чтобы ошибка не повторялась при следующем запуске. </div>\n",
    "\n",
    "<h4 style=\"text-align:center; margin-top:20px\"><u>Чем пользоваться, рекурсией или циклом?</u></h4>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\">Недостатки выше — не повод отказываться от рекурсивных решений совсем. Просто в каждом случае, где можно применить рекурсию, разработчик должен спрашивать себя, оптимально это или нет. </div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify\">Если программе важна высокая скорость работы и низкая нагрузка или существует риск переполнения памяти — лучше выбрать вариант без рекурсии. </div>\n",
    "<div style=\"text-indent:30px; text-align:justify\">Если скорость не так важна, а реализация без рекурсии отнимет много времени и строк кода — лучше воспользоваться рекурсивным подходом. </div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\">Понимание, что лучше использовать в конкретном случае, приходит с опытом. Начинающим разработчикам в любом случае стоит освоить рекурсию: это важная часть программирования и информатики вообще. </div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\">И, наконец, рекурсию можно встретить не только в программировании. </div>\n",
    "<div style=\"text-indent:30px; text-align:justify\">Это вполне распространенное явление даже в повседневной жизни (<a href=\"https://skillbox.ru/media/code/rekursiya-vokrug-nas/?ysclid=m8znkv19ae16983305\"><strong>ссылка</strong></a> и еще одна <a href=\"https://javarush.com/groups/posts/465-dnju-surka-posvjajshaetsja-rekursija-v-realjhnoy-zhizni-?ysclid=m8znr6etne723857051\"><strong>ссылка</strong></a>). </div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h2 style=\"text-align:center; margin-top:30px\">Анонимные функции (<strong>lambda</strong>-выражения)</h2>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify\">В языке Python можно создавать функции с уникальными именами, но иногда имя не требуется. Например, функциям, использующимся единственный раз. В таких случаях применяют анонимные функции. </div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\">Помимо стандартного определения функции, состоящего из заголовка с ключевым словом <strong>def</strong> и блока кода – тела функции, в Python можно создавать короткие однострочные функции с использованием ключевого слова <strong>lambda</strong>. Это анонимные функции или лямбда-функции (<i>lambda-выражения</i>). </div>\n",
    "\n",
    "<table style=\"border:groove; margin-top:20px; margin-left:80px; margin-right:80px\">\n",
    "    <tr>\n",
    "        <td style=\"background:LightCyan; height:60px\">\n",
    "            <div style=\"margin-left:30px; font-size:larger; line-height:26px\"><img alt=\"\" src=\"nerd-face.png\" style=\"float: left; margin-right:20px\" width=\"30\"; height=\"30\"><strong>Анонимные функции – функции с телом, но без имени.</strong></div>\n",
    "        </td>\n",
    "    </tr>\n",
    "</table>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px; margin-bottom:20px\"><strong>Lambda-выражение может принимать любое количество аргументов, но оно всегда возвращает одно выражение. </strong></div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify\">Общий формат определения анонимной функции: <strong>lambda <i>список_параметров</i>: <i>выражение</i></strong>. </div>\n",
    "\n",
    "<div style=\"text-indent:60px; text-align:justify\"><strong><i>список_параметров</i></strong> – список параметров через запятую; </div>\n",
    "<div style=\"text-indent:60px; text-align:justify\"><strong><i>выражение</i></strong> – значение, либо код, дающий значение. </div>\n",
    "\n",
    "<table style=\"border:groove; margin-top:20px; margin-left:80px; margin-right:80px\">\n",
    "    <tr>\n",
    "        <td style=\"background:LightCyan; height:60px\">\n",
    "            <div style=\"margin-left:30px; font-size:larger; line-height:26px\"><img alt=\"\" src=\"shocked-face.png\" style=\"float: left; margin-right:20px\" width=\"30\"; height=\"30\"><strong>Параметры анонимных функций, в отличие от обычных, не нужно заключать в скобки.</strong></div>\n",
    "        </td>\n",
    "    </tr>\n",
    "</table>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\">Следующие два определения функций эквивалентны: </div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "def standard_function(x):            #  Стандартное объявление функции\n",
    "    return x*2\n",
    "\n",
    "lambda_function = lambda x: x*2      #  Объявление анонимной функции"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div style=\"text-indent:30px; text-align:justify\">Приведенный ниже код вводит одинаковый результат для обеих функций: </div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "14\n",
      "14\n"
     ]
    }
   ],
   "source": [
    "print(standard_function(7))\n",
    "print(lambda_function(7))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\">Рассмотрим еще примеры. Приведенный ниже код: </div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "30\n",
      "15\n",
      "45\n"
     ]
    }
   ],
   "source": [
    "f1 = lambda: 10 + 20               # Функция без параметров\n",
    "f2 = lambda х, у: х + у            # Функция с двумя параметрами\n",
    "f3 = lambda х, у, z: х + у + z     # Функция с тремя параметрами\n",
    "\n",
    "print(f1())\n",
    "print(f2(5, 10))\n",
    "print(f3(5, 10, 30))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\"><u>Когда применение анонимных функций оправдано: </u></div>\n",
    "\n",
    "<div style=\" margin-left:50px\">\n",
    "<li style=\"text-align:justify\">однократное использование простых функции;</li>\n",
    "<li style=\"text-align:justify\">передача функций в качестве аргументов другим функциям;</li>\n",
    "<li style=\"text-align:justify\">возвращение функции в качестве результата другой функции.</li>\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "25\n",
      "27\n",
      "1024\n"
     ]
    }
   ],
   "source": [
    "def create_power_function(stepen): # Функция возвращает анонимную функцию для возведения в степень stepen\n",
    "    return lambda x: x**stepen\n",
    "\n",
    "# Создаем функции\n",
    "square_function = create_power_function(2)   # Функция возведения в квадрат\n",
    "cube_function   = create_power_function(3)   # Функция возведения в куб\n",
    "dozen_function  = create_power_function(10)  # Функция возведения в десятую степень\n",
    "\n",
    "# Проверяем функции\n",
    "print(square_function(5))   # 5**2  = 25\n",
    "print(cube_function(3))     # 3**3  = 27\n",
    "print(dozen_function(2))    # 2**10 = 27"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div style=\"text-indent:30px; text-align:justify\">В этом коде функция <strong>create_power_function</strong> принимает один параметр <strong>stepen</strong> и возвращает <strong><u><i>анонимную функцию</i></u></strong>, которая возводит переданное значение <strong>x</strong> в степень, указанную в аргументе <strong>stepen</strong>. </div>\n",
    "    \n",
    "<div style=\"text-indent:30px; text-align:justify\">Далее мы создаем три функции: <strong>square_function</strong> для возведения в квадрат, <strong>cube_function</strong> для возведения в куб и <strong>dozen_function</strong> для возведения в десятую степень. </div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify\">Анонимные функции, возвращаемые из других функций, позволяют создавать гибкие и удобные для использования конструкции, что делает код более читаемым и компактным. </div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h4 style=\"text-align:center; margin-top:20px\"><u>Условный оператор в теле анонимной функции</u></h4>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\">В теле анонимной функции не получится выполнить несколько действий и не получится использовать многострочные конструкции вроде циклов for и while. Однако можно использовать <a href=\"https://ru.wikipedia.org/wiki/%D0%A2%D0%B5%D1%80%D0%BD%D0%B0%D1%80%D0%BD%D0%B0%D1%8F_%D1%83%D1%81%D0%BB%D0%BE%D0%B2%D0%BD%D0%B0%D1%8F_%D0%BE%D0%BF%D0%B5%D1%80%D0%B0%D1%86%D0%B8%D1%8F\"><strong>тернарный условный оператор</strong></a>. </div>\n",
    "\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\">Общий вид тернарного условного оператора в теле анонимной функции выглядит так: </div>\n",
    "\n",
    "<div style=\"text-indent:60px; text-align:justify\"><i>значение-1</i> <strong>if</strong> <i>условие</i> <strong>else</strong> <i>значение-2</i>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\">Пример: </div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "5\n"
     ]
    }
   ],
   "source": [
    "# Lambda выражение, которое возвращает большее из двух чисел\n",
    "max_num = lambda x, y: x if x > y else y\n",
    "\n",
    "print(max_num(3, 5))   # Вывод: 5"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div style=\"text-indent:30px; text-align:justify\">В этом примере, если <strong>x</strong> больше <strong>y</strong>, возвращается <strong>x</strong>, иначе возвращается <strong>y</strong>. </div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\">Тернарный оператор позволяет создавать компактные и читаемые условия внутри lambda-выражений, что делает их более гибкими и мощными. </div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify; margin-top:20px\">В качестве следующего примера создадим lambda-выражение, которое классифицирует число как положительное, отрицательное или ноль:</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Положительное\n",
      "Отрицательное\n",
      "Ноль\n"
     ]
    }
   ],
   "source": [
    "classify_number = lambda x: 'Положительное' if x > 0 else ('Отрицательное' if x < 0 else 'Ноль')\n",
    "print(classify_number(10))   # Вывод: Положительное\n",
    "print(classify_number(-5))   # Вывод: Отрицательное\n",
    "print(classify_number(0))    # Вывод: Ноль"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div style=\"text-indent:30px; text-align:justify\">В заключение рассмотрим пример для самых продвинутых:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[5, 4, 3, 2, 1]\n"
     ]
    }
   ],
   "source": [
    "numbers = [1, 2, 5, 3, 4]\n",
    "numbers.sort(key=lambda x: -x)\n",
    "print(numbers)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div style=\"text-indent:30px; text-align:justify\">Сначала создается список <strong>numbers</strong>, который содержит пять чисел. </div>\n",
    "                                                                                                                     \n",
    "<div style=\"text-indent:30px; text-align:justify\">После этого вызывается метод <strong>sort()</strong> на этом списке. </div>\n",
    "    \n",
    "<div style=\"text-indent:30px; text-align:justify\">Метод <strong>sort()</strong> используется для сортировки элементов списка в порядке возрастания или убывания. По умолчанию элементы сортируются в порядке возрастания, но мы можем указать собственный критерий сортировки с помощью параметра <strong>key</strong>. </div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify\">В данном случае в качестве значения параметра <strong>key</strong> используется лямбда-функция <strong>lambda x: -x</strong>. Лямбда-функция представляет собой анонимную функцию, которая принимает один аргумент <strong>x</strong> и возвращает его отрицательное значение <strong>-x</strong>. Это означает, что при сортировке список будет рассматриваться не в исходном виде, а с измененными значениями (отрицательные значения каждого элемента списка). </div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify\">Когда метод <strong>sort()</strong> применяет эту лямбда-функцию ко всем элементам списка, он фактически переворачивает их знаки, и получается следующий порядок на основе этих новых значений: </div>\n",
    "\n",
    "<div style=\" margin-left:50px\">\n",
    "<li style=\"text-align:justify\">для 1 будет -1;</li>\n",
    "<li style=\"text-align:justify\">для 2 будет -2;</li>\n",
    "<li style=\"text-align:justify\">для 3 будет -3;</li>\n",
    "<li style=\"text-align:justify\">для 4 будет -4;</li>\n",
    "<li style=\"text-align:justify\">для 5 будет -5.</li>\n",
    "</div>\n",
    "\n",
    "<div style=\"text-indent:30px; text-align:justify\">Следовательно, если сортировать список по убыванию, то в итоге получим порядок на основе положительных значений: 5, 4, 3, 2, 1. </div>"
   ]
  }
 ],
 "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.12.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
