Привычные арифметические действия (сложение, вычитание, умножение, деление) в Python выглядят так же, как и в обычных калькуляторах:
2 + 5 # сложение
2 * 8 - 9 # умножение и вычитание
9 / 2 # деление
Однако с делением всё не так просто: Python 3 всегда будет выдавать результат в виде числа с плавающей точкой (такой тип данных называется float), даже тогда, когда ожидается целочисленный ответ. Например:
8 / 2 # не 4
Получился дробный результат, где дробная часть равна 0. Как быть, если нужен ответ в виде целого числа? Можно воспользоваться целочисленным делением — оператором //
:
8 // 2 # теперь 4
Тут важно помнить, что при использовании оператора //
дробная часть всегда будет просто отбрасываться – никакого округления происходить не будет. Для округления (обычное арифметическое, в большую и в меньшую сторону) существуют специальные функции, и мы их обсудим позже.
9 // 2 # от 4.5 осталось 4
Что еще можно делать с числами? Возводить в степень и извлекать из них корень. При расчетах на калькуляторе для возведения числа в степень мы обычно используем символ ^
. Попробуем!
9 ^ 2
Получилось что-то неожиданное. В Python оператор ^
используется для побитного сложения по модулю два (операция интересная, но нам она нигде не понадобится). Для возведения числа в степень потребуется оператор **
:
9 ** 2
10 ** 3
27 ** (1/3) # дробная степень - корень 3 степени
Теперь попробуем извлечь квадратный корень из числа с помощью привычного sqrt
.
sqrt(16) # не получается!
Python пишет, что не знает, что такое sqrt
. В каких случаях Python может такое писать? Чаще всего в двух случаях:
В данном случае мы столкнулись со второй проблемой. Функция sqrt()
для вычисления квадратного корня из числа хранится в специальном модуле math
. Этот модуль стандартный, дополнительно устанавливать его не нужно. Но для того, чтобы воспользоваться этой функцией, нужно сначала импортировать модуль, а потом вызвать из него функцию sqrt
. Давайте импортируем модуль math
:
import math
А теперь из этого модуля вызовем функцию sqrt()
:
math.sqrt(16) # теперь все работает
Если из math
нам нужна только одна функция sqrt
, можно извлечь только её, и тогда прописывать название модуля перед функцией не понадобится:
from math import sqrt
sqrt(16) # так тоже работает
В math
есть много полезных функций для вычислений. Чтобы посмотреть, какие функции там есть, после импортирования всего модуля через import math
можно набрать math.
и нажать на Tab (табуляция, кнопка над Caps Lock). Помимо квадратного корня этот модуль поможет вычислять логарифмы, синусы, косинусы и так далее. Остановимся на логарифмах, так как именно операция логарифмирования часто встречается в обработке и анализе данных.
Напоминание. Выражение $\log_{a}(b)$ («логарифм от $b$ по основанию $a$») подразумевает следующий вопрос: в какую степень нужно возвести число $a$, чтобы получить $b$? Например, $\log_{4}(16)=2$, так как $4^2=16$, а $\log_{2}{32}=5$, так как $2^5=32$.
В анализе данных чаще используются натуральный (по основанию $e\approx2.718$) и десятичный (по основанию 10) логарифмы. Зачем логарифмирование нужно в анализе данных, мы обсудим позже, а пока посмотрим на их вычисление в Python:
math.log(27, 3) # логарифм по основанию 3
math.log(12) # натуральный логарифм
math.log10(10000) # десятичный логарифм
В модуле math
также хранятся функции для округления в большую или меньшую сторону:
math.ceil(4.2) # от ceil - потолок
math.floor(4.6) # от floor - пол
Для обычного округления используется базовая, не встроенная в math
функция round()
:
round(4.7)
С чем ещё можно столкнуться, выполняя вычисления в Python? С такими вещами:
1 / 18 ** 25
Результат выше – компьютерная форма экспоненциальной записи числа. Возможно, тот, кто считал что-то на научных или инженерных калькуляторах, уже сталкивался с такой записью. Здесь e-32
– это $10^{-32}$, а вся запись означает $4.1513310942010236 \cdot 10^{-32}$, то есть примерно $4.15 \cdot 10^{-32}$. Теоретически, если число было очень большим, e
стояло бы в положительной степени. Но в Python такое не случается, обычно он выводит огромные числа, просто переходя на новую строку, если места на одной не хватает:
23 ** 990
Компьютерная форма записи числа отчасти помогает понять, почему дробные числа называются числами с плавающей точкой (тип float). Возьмем число попроще, например, $12.34$. Его можно записать как $12.34$, как $1.234 \cdot 10$, как $123.4 \cdot 10^{-1}$, $1234 \cdot 10^{-2}$ и так далее. Точка, отделяющая дробную часть от целой, будет «плавать», однако само число при этом меняться не будет, будут меняться только множители – разные степени десятки.
С числами с плавающей точкой связана ещё одна сложность — округление. На первый взгляд, всё хорошо:
round(12.6) # округлим до целого - по умолчанию
round(12.53, 1) # округлим до первого знака после запятой
С другой стороны, могут возникнуть странности:
round(2.50) # не 3
round(3.525, 2) # не 3.53
Эти странности связаны с тем, что число, которое мы видим (например, 3.525), не совпадает с тем, которое хранится в компьютере, потому что оно при сохранении преобразовывается и превращается из точного 3.525 в такое:
from decimal import Decimal
Decimal(3.525)
И такое число будет законно округляться до 3.52 по правилам арифметического округления. В прикладном анализе данных такие сложности редко вызывают проблемы, но знать про нее полезно, чтобы не пугаться и не удивляться неожиданным результатам. Кроме того, полезно помнить, что числа с плавающей точкой (типа float) не рекомендуется использовать в финансовых вычислениях и вообще в вычислениях, требующих высокой точности, поскольку они «накапливают ошибку», то есть дают неточные результаты.
Переменные в программировании похожи на переменные в математике. Кроме того, их можно рассматривать как хранилища значений – контейнеры или «коробки», в которые мы что-то кладем. Python, в отличие от некоторых языков программирования (C, C++, Java), сам распознает что мы «кладем в коробку»: число, целое число, текст, список чисел... Поэтому при создании переменной нам не нужно указывать ее тип.
x = 2 # Python поймет, что это целые числа
y = 3
print(x)
print(y)
Значения переменных мы можем обновлять – изменить значение и сохранить в переменную с тем же названием.
x = x + 1 # возьмем значение x, увеличим на 1 и сохраним изменения в переменной x
y = y * 2 # возьмем значение y, увеличим в 2 раза и сохраним изменения
print(x, y) # одновременно два значения
Названия переменных в Python могут быть почти любыми. Три общих правила: название переменной не должно начинаться с цифры, в названии не должно быть пробелов, название не должно совпадать со служебными (зарезервированными) словами в Python. Список зарезервированных слов можно узнать так:
import keyword
print(keyword.kwlist)
Обычно рекомендуется давать переменным осмысленные названия: если речь идёт о доходе, называть переменную не x
, а income
, если речь идёт о данных по преступности, сохранять таблицу в переменную crimes
, и так далее. Технически, Python 3 допускает названия на кириллице, но это будет выглядеть странно и неуместно.
Рассмотрим такую задачу. Пришла весна и решили мы заняться бегом по такой схеме: каждый день мы пробегаем столько, сколько в сумме за два предыдущих дня. При этом первые два дня мы морально готовимся: топчемся на месте и символически проходим по одному метру (полшага назад и полшага вперед). Если мы будем записывать все пройденные нами расстояния в ряд, мы получим последовательность из чисел Фибоначчи. Давайте напишем код, который будет считать, сколько метров мы будем пробегать в следующий день.
Сначала создадим переменные, в которые сохраним данные по первым двум дням.
b = 1 # день 1 - морально готовимся бегать, «бежим» 1 метр
i = 1 # номер дня, когда начинаем бегать
bnext = 1 # день 2 - снова морально готовимся бегать, «бежим» 1 метр
i = i + 1 # перешли ко второму дню, увеличили i на 1
res = b + bnext # в следующий день пробегаем столько же, сколько за два предыдущих
i = i + 1 # перешли к следующему дню, увеличили i на 1
b = bnext # значение b нам уже не нужно, сдвигаемся к следующему дню - записываем bnext
bnext = res # запомнили полученное значение res
print(i, bnext) # выводим на экран номер дня и расстояние, которое нужно пробежать
Теперь можно прогонять предыдущую ячейку много раз (через Ctrl + Enter) и получать результат по каждому дню. Например, на 20 день мы будем пробегать уже нормальное расстояние — 6765 метров, почти 7 километров. Конечно, прогонять одну и ту ячейку много раз неудобно и странно, но о том, как считать числа Фибоначчи более рационально, мы поговорим, когда будем разбирать циклы.
Важно: если бы не разбили наш код на части (на две ячейки), ничего бы при повторном запуске ячейки не произошло — переменным b
, bnext
и i
заново присваивались бы значения 1, и движения вперед бы не происходило.
Примечание: можно было последней строкой написать print(i, res)
, ничего бы не изменилось.