{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Базовые типы: численные типы #"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "На этой лекции мы начинаем знакомство с основными базовыми типами, которые есть в Python.\n",
    "\n",
    "## Целые числа (int) ##\n",
    "\n",
    "Первым в нашем списке будет идти тип int, это целые числа. Чтобы объявить целое число достаточно писать `num = 13`, тем самым мы связываем имя переменной `num` с малочисленным объектом со значением 13, точно также можно присвоить переменной 0 либо отрицательно целое число."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "num = 13\n",
    "num = 0\n",
    "num = -1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Начиная с Python 3.6 появилась возможность разделять порядки символом нижнего подчеркивания в длинных числах, тем самым мы можем улучшить читаемость этих чисел в исходном коде."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "kpop = 10_000_000"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Раз уж мы заговорили о длинных числах, стоит отметить, что Python поддерживает длинную арифметику при работе с целыми числами, то есть поддерживаются числа неограниченной длины. Прежде чем продолжить, давайте разберем еще одну встроенную функцию, которая есть в языке, это функция `Type`. Функция `type` доступна в глобальном пространстве имен и она позволяет в рантайме, в процессе работы программы посмотреть на тип объекта, если мы объявим переменную `num` и свяжем ее с малочисленным объектом 13, а затем посмотрим какой у неё тип, то мы увидим, что это класс `int`, то это действительно тип `integer` и в дальнейшем мы видим, что встроенные типы Python они реализованы как классы, об этом я буду говорить в третьем блоке нашего курса. Ну а сейчас просто важно запомнить, что функция `Type` позволяет увидеть тип объекта."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "int"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "type(kpop)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Вещественные числа (float) ##\n",
    "\n",
    "Также Python умеет работать с вещественными числами, то есть с числами с плавающей точкой, это тип `float`. Чтобы объявить вещественное число, можно написать `pi = 13.4`, то есть точка используется для того чтобы разделить целую и дробную часть вещественного числа, то же самое для 0, и то же самое для отрицательного вещественного числа. По аналогии с типом `int` мы можем использовать символ нижнего подчёркивания, для того, чтобы разделять порядки в длинном вещественном числе. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "pi = 13.4\n",
    "e = 2.718_281_828_459_045"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Также Python поддерживает экспоненциальную нотацию записи вещественного числа, а, как мы можем видеть `1.5Е2`, на самом деле это полтора, умножить на 10 в степени 2, то есть 150."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "150.0"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "1.5E2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "150.0"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "1.5 * 10 ** 2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Конвертация типов ##\n",
    "\n",
    "Теперь поговорим о ещё одном важном аспекте - о конвертации типов. Посмотрим на пример, предположим, у нас есть переменная `num`, которая связана с вещественным объектом со значением 150,2, и мы видим что это тип `float`. В любой момент мы можем воспользоваться встроенным классом `int`, чтобы переменную, которая связана с типом `float`, перевести в объект типа `integer` и затем мы можем преобразовать `integer` обратно к вещественному типу, используя класс `float`, тем самым в процессе работы программы мы можем из одного типа конвертировать переменные в другой тип."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "150.2"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "num = 150.2\n",
    "num"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "150"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "num = int(num)\n",
    "num"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "150.0"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "float(num)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Обратите внимание, что в процессе наших конвертаций на примере, мы потеряли дробную часть вещественного числа.\n",
    "\n",
    "## Комплексные числа (complex) ##\n",
    "\n",
    "Также Python умеет работать с комплексными числами, это тип комплекс, для того, чтобы определить комплексное число нужно для мнимой части использовать символ `J`, посмотрите на пример, мы определили комплексное число `14 + 1J` и можем убедиться, что его тип действительно комплекс, используя встроенную функцию `Type`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(14+1j)"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "num = 14 + 1J\n",
    "num"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "complex"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "type(num)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "А также, чтобы достучаться до реальной и мнимой части комплексного числа, мы можем воспользоваться атрибутами `real` и `imag`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 109,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "14.0"
      ]
     },
     "execution_count": 109,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "num = 14 + 1J\n",
    "num.real"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1.0"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "num.imag"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Что стоит отметить? Что в Pyton-e есть еще два модуля, которые позволяют работать с числами, эти модули очень полезны, мы не будем рассматривать их подробно, но знать о них нужно. В первую очередь, это модуль `deccimal`, который позволяет работать с вещественными числами с фиксированной точностью, а второй модуль это модуль `fractions`, который позволяет работать с рациональными числами, проще говоря с дробями.\n",
    "\n",
    "## Основные операции с числами ##\n",
    "\n",
    "Теперь посмотрим на основные операции с числами, как я уже говорил, Python хорош в качестве калькулятора и, конечно же, он умеет работать с числами очень хорошо. Для того, чтобы сложить два числа, мы используем просто математический оператор плюс. 1+1=2, сумма двух целых чисел дает нам целое число, если мы складываем целое число и вещественное число, то результат у нас получается вещественный. То же самое с вычитанием, если мы вычитаем из целого целое, получается целое число, если мы вычитаем из вещественного целое, то результат вещественный. Для того, чтобы разделить числа, мы можем воспользоваться символом прямого слэша, и обратите внимание, что результат деления всегда вещественный. Делить на 0 нельзя. Если мы попытаемся разделить на 0, то мы получим исключение `ZeroDivisionError`. Про исключения, как я уже говорил, мы с вами будем говорить в дальнейшем, научим вас их отлавливать и обрабатывать. Для того чтобы умножить числа, мы можем использовать звездочку, а для того, чтобы возвести число в степень, мы можем использовать две звездочки, на примере мы возводим число 2 в 4 степень. Чтобы произвести целочисленное деление, мы используем два прямых слэша. Чтобы получить остаток от деления, используем процент. Важно подчеркнуть, что Python использует порядок операций в выражениях с числами такой, какой используется в правилах математики и,в если мы посмотрим на пример, то выражение 3 плюс 10 умножить на 3, сначала выполнится умножение, а потом сложение. Если же нам нужно подчеркнуть, что нужно сначала выполнить сложение, а потом результат сложения умножить на 3, то мы можем воспользоваться круглыми скобочками для этого."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Сложение:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "1 + 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2.5"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "1 + 1.5"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Вычитание:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "6 - 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4.0"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "6 - 2.0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Деление:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3.0"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "6 / 2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Делить на 0 нельзя:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "ename": "ZeroDivisionError",
     "evalue": "division by zero",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mZeroDivisionError\u001b[0m                         Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-36-35ab704efce5>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[1;36m6\u001b[0m \u001b[1;33m/\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mZeroDivisionError\u001b[0m: division by zero"
     ]
    }
   ],
   "source": [
    "6 / 0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Умножение:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "6"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "2 * 3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Возведение числа в степень:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "16"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "2 ** 4"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Целочисленное деление:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "10 // 3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Остаток от деления:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "10 % 3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Порядок операций в выражениях с числами:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "33"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "3 + 10 * 3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "39"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(3 + 10) * 3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Побитовые операции ##\n",
    "\n",
    "Также Python поддерживает побитовые операции для чисел, среди них побитово или, побитово исключающие или, и так далее."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Побитовое или: 7\n",
      "Побитовое исключающее или: 7\n",
      "Побитовое и: 0\n",
      "Битовый сдвиг влево: 32\n",
      "Битовый сдвиг вправо: 2\n",
      "Инверсия битов: -5\n"
     ]
    }
   ],
   "source": [
    "x = 4\n",
    "y = 3\n",
    "\n",
    "print(\"Побитовое или:\", x | y)\n",
    "print(\"Побитовое исключающее или:\", x ^ y)\n",
    "print(\"Побитовое и:\", x & y)\n",
    "print(\"Битовый сдвиг влево:\", x << 3)\n",
    "print(\"Битовый сдвиг вправо:\", x >> 1)\n",
    "print(\"Инверсия битов:\", ~x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "tags": []
   },
   "source": [
    "## Задачка ##\n",
    "\n",
    "Теперь посмотрим на задачку. Задача найти расстояние между двумя точками в декартовых координатах, эта задача известна всем нам из школьного курса математики, и для того, чтобы ее решить по большому счёту, нам нужно найти гипотенузу прямоугольного треугольника. Давайте посмотрим на решение на Python.\n",
    "\n",
    "![График](graph.svg \"График\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "5.0\n"
     ]
    }
   ],
   "source": [
    "x1, y1 = 0, 0\n",
    "x2 = 3\n",
    "y2 = 4\n",
    "\n",
    "distance = ((x2 - x1) ** 2 + (y2 - y1) ** 2) ** .5\n",
    "print(distance)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Вначале мы объявляем переменные, это координаты точек. Обратите внимание на самую верхнюю запись `x1, y1 = 0, 0`. Это синтаксис, который поддерживается Python'ом, он позволяет через запятую перечислить названия переменных, а далее, через запятую перечислить те значения, которые этим переменным нужно присвоить. Это очень удобно. Для того, чтобы найти расстояние, мы воспользуемся формулой, корень из суммы квадратов катетов, и здесь мы видим, как мы вычисляем расстояние. Вместо того, чтобы брать корень, мы возводим выражение в скобках в степени 0,5, что эквивалентно взятию корня. И далее печатаем на экран ответ, мы видим, что ответ получился правильный."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "А что ещё хочется отметить про синтаксис Python, это мы видели в предыдущем примере то, что можно на одной строчке присвоить значения нескольким переменным. Однако, тот же самый трюк позволяет, например, поменять значения у 2 переменных без использования временной переменной, то есть мы определяем две переменные, дальше пишем `a, b = b, a`, и значение переменных меняется местами. Также очень удобно."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2 1\n"
     ]
    }
   ],
   "source": [
    "a = 1\n",
    "b = 2\n",
    "a, b = b, a\n",
    "\n",
    "print(a, b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Что еще можно сделать было бы? Мы могли бы записать вместо `a, b = 0, 0`, `a = b = 0`, тем самым мы бы связали переменную `a` и переменную `b` с объектом, с зачисленным объектом 0. Однако нужно быть внимательным. первый объект это изменяемый объект, а второй - это неизменяемые, изменяемые объекты это объекты, которые после создания могут менять свое значение, а неизменяемые, соответственно, это объекты, которые после создания свое значение не меняют. Примитивные основные типы, которые мы разбираем на этой неделе, по большому счету, не изменяемы, поэтому для нашей задачи запись `a = b = 0` была бы оправдана. В данном случае, если бы мы поменяли только `a`, например, добавили бы к `a` впоследствии единичку, у нас `a` стал бы равен 1, а `b` остался бы нулем."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 0\n"
     ]
    }
   ],
   "source": [
    "a = b = 0\n",
    "a += 1\n",
    "\n",
    "print(a, b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Но если бы мы написали `a = b = пустой список`, а пустой список - это объект-контейнер, который мы будем разбирать на дальнейших неделях, он позволяет хранить последовательность объектов в себе, а этот объект уже изменяемый, поэтому, когда мы присваиваем `a = b = пустой список`, а затем в список `a` добавляем два элемента, то, если мы выведем на экран `a` и `b`, то мы увидим, что изменились значения обеих переменных. С этим нужно быть внимательным, это нюанс, который необходимо понимать и необходимо понимать, что в Python-е есть неизменяемые объекты и изменяемые объекты."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2] [1, 2]\n"
     ]
    }
   ],
   "source": [
    "a = b = list()\n",
    "\n",
    "a.append(1)\n",
    "a.append(2)\n",
    "\n",
    "print(a, b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "На этой лекции мы с вами поговорили об основных численных типах, которые есть в языке, рассмотрели математические операции с ними, узнали о конвертации типов, а также затронули тему изменяемых и не изменяемых объектов в Python. В дальнейших лекциях, мы продолжим знакомиться с основными типами в языке.\n",
    "\n",
    "[Далее...](Логический%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
}
