Привычные арифметические действия (сложение, вычитание, умножение, деление) в Python выглядят так же, как и в обычных калькуляторах:
2 + 5 # сложение
7
2 * 8 - 9 # умножение и вычитание
7
9 / 2 # деление
4.5
Однако с делением всё не так просто: Python 3 всегда будет выдавать результат в виде числа с плавающей точкой (такой тип данных называется float), даже тогда, когда ожидается целочисленный ответ. Например:
8 / 2 # не 4
4.0
Получился дробный результат, где дробная часть равна 0. Как быть, если нужен ответ в виде целого числа? Можно воспользоваться целочисленным делением — оператором //
:
8 // 2 # теперь 4
4
Тут важно помнить, что при использовании оператора //
дробная часть всегда будет просто отбрасываться – никакого округления происходить не будет. Для округления (обычное арифметическое, в большую и в меньшую сторону) существуют специальные функции, и мы их обсудим позже.
9 // 2 # от 4.5 осталось 4
4
Что еще можно делать с числами? Возводить в степень и извлекать из них корень. При расчетах на калькуляторе для возведения числа в степень мы обычно используем символ ^
. Попробуем!
9 ^ 2
11
Получилось что-то неожиданное. В Python оператор ^
используется для побитного сложения по модулю два (операция интересная, но нам она нигде не понадобится). Для возведения числа в степень потребуется оператор **
:
9 ** 2
81
10 ** 3
1000
27 ** (1/3) # дробная степень - корень 3 степени
3.0
Теперь попробуем извлечь квадратный корень из числа с помощью привычного sqrt
.
sqrt(16) # не получается!
--------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-11-5ab95dccb11e> in <module> ----> 1 sqrt(16) # не получается! NameError: name 'sqrt' is not defined
Python пишет, что не знает, что такое sqrt
. В каких случаях Python может такое писать? Чаще всего в двух случаях:
В данном случае мы столкнулись со второй проблемой. Функция sqrt()
для вычисления квадратного корня из числа хранится в специальном модуле math
. Этот модуль стандартный, дополнительно устанавливать его не нужно. Но для того, чтобы воспользоваться этой функцией, нужно сначала импортировать модуль, а потом вызвать из него функцию sqrt
. Давайте импортируем модуль math
:
import math
А теперь из этого модуля вызовем функцию sqrt()
:
math.sqrt(16) # теперь все работает
4.0
Если из math
нам нужна только одна функция sqrt
, можно извлечь только её, и тогда прописывать название модуля перед функцией не понадобится:
from math import sqrt
sqrt(16) # так тоже работает
4.0
В 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
3.0
math.log(12) # натуральный логарифм
2.4849066497880004
math.log10(10000) # десятичный логарифм
4.0
В модуле math
также хранятся функции для округления в большую или меньшую сторону:
math.ceil(4.2) # от ceil - потолок
5
math.floor(4.6) # от floor - пол
4
Для обычного округления используется базовая, не встроенная в math
функция round()
:
round(4.7)
5
С чем ещё можно столкнуться, выполняя вычисления в Python? С такими вещами:
1 / 18 ** 25
4.1513310942010236e-32
Результат выше – компьютерная форма экспоненциальной записи числа. Возможно, тот, кто считал что-то на научных или инженерных калькуляторах, уже сталкивался с такой записью. Здесь e-32
– это $10^{-32}$, а вся запись означает $4.1513310942010236 \cdot 10^{-32}$, то есть примерно $4.15 \cdot 10^{-32}$. Теоретически, если число было очень большим, e
стояло бы в положительной степени. Но в Python такое не случается, обычно он выводит огромные числа, просто переходя на новую строку, если места на одной не хватает:
23 ** 990
12899047957225248523006646539464335721979411301041340884781899303831010765027442196396594170642790934375007246578677182803636590164161819235523359334210795997877313526230138186880373768216363562984711930606834390635683889567066017501638286295454450223592921380025243612655929972891854670089005958782301313748919257409270999076443855743717129316401343809648755190213387432370099603517989905917859013302341878321325941570315088698234189444110362237214217846884135935952399097352427521852877620725021626938113437232848226058128334528859922677792198697568021708059256675191088006467069748109014817451375952598349790911535607651796493584493889427435570940502359773301622881259890983839926411232560174739455589741388073805529446667461505169110660161765843273557623843219490805708791092602475974648916336329253754550331716502327365416889998212147857020330942368277430427804385066546271943413689950822020931400593245046303758610973943882235592749794293155060009636680119916358947879472882782808870076229635495297702820410851089251120079429452529354919596272075046635023793735251154878700529432000342403111069160632592433095161936605646694694109530441088995393229754160740330575038216906404744009495445586324655891258721903641299986081018110880120922925030222636715904777957341225983442938451506259053249716900875692689602609775497863867095485915444153828849
Компьютерная форма записи числа отчасти помогает понять, почему дробные числа называются числами с плавающей точкой (тип float). Возьмем число попроще, например, $12.34$. Его можно записать как $12.34$, как $1.234 \cdot 10$, как $123.4 \cdot 10^{-1}$, $1234 \cdot 10^{-2}$ и так далее. Точка, отделяющая дробную часть от целой, будет «плавать», однако само число при этом меняться не будет, будут меняться только множители – разные степени десятки.
С числами с плавающей точкой связана ещё одна сложность — округление. На первый взгляд, всё хорошо:
round(12.6) # округлим до целого - по умолчанию
13
round(12.53, 1) # округлим до первого знака после запятой
12.5
С другой стороны, могут возникнуть странности:
round(2.50) # не 3
2
round(3.525, 2) # не 3.53
3.52
Эти странности связаны с тем, что число, которое мы видим (например, 3.525), не совпадает с тем, которое хранится в компьютере, потому что оно при сохранении преобразовывается и превращается из точного 3.525 в такое:
from decimal import Decimal
Decimal(3.525)
Decimal('3.524999999999999911182158029987476766109466552734375')
И такое число будет законно округляться до 3.52 по правилам арифметического округления. В прикладном анализе данных такие сложности редко вызывают проблемы, но знать про нее полезно, чтобы не пугаться и не удивляться неожиданным результатам. Кроме того, полезно помнить, что числа с плавающей точкой (типа float) не рекомендуется использовать в финансовых вычислениях и вообще в вычислениях, требующих высокой точности, поскольку они «накапливают ошибку», то есть дают неточные результаты.
Переменные в программировании похожи на переменные в математике. Кроме того, их можно рассматривать как хранилища значений – контейнеры или «коробки», в которые мы что-то кладем. Python, в отличие от некоторых языков программирования (C, C++, Java), сам распознает что мы «кладем в коробку»: число, целое число, текст, список чисел... Поэтому при создании переменной нам не нужно указывать ее тип.
x = 2 # Python поймет, что это целые числа
y = 3
print(x)
print(y)
2 3
Значения переменных мы можем обновлять – изменить значение и сохранить в переменную с тем же названием.
x = x + 1 # возьмем значение x, увеличим на 1 и сохраним изменения в переменной x
y = y * 2 # возьмем значение y, увеличим в 2 раза и сохраним изменения
print(x, y) # одновременно два значения
3 6
Названия переменных в Python могут быть почти любыми. Три общих правила: название переменной не должно начинаться с цифры, в названии не должно быть пробелов, название не должно совпадать со служебными (зарезервированными) словами в Python. Список зарезервированных слов можно узнать так:
import keyword
print(keyword.kwlist)
['False', 'None', 'True', 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']
Обычно рекомендуется давать переменным осмысленные названия: если речь идёт о доходе, называть переменную не 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) # выводим на экран номер дня и расстояние, которое нужно пробежать
3 2
Теперь можно прогонять предыдущую ячейку много раз (через Ctrl + Enter) и получать результат по каждому дню. Например, на 20 день мы будем пробегать уже нормальное расстояние — 6765 метров, почти 7 километров. Конечно, прогонять одну и ту ячейку много раз неудобно и странно, но о том, как считать числа Фибоначчи более рационально, мы поговорим, когда будем разбирать циклы.
Важно: если бы не разбили наш код на части (на две ячейки), ничего бы при повторном запуске ячейки не произошло — переменным b
, bnext
и i
заново присваивались бы значения 1, и движения вперед бы не происходило.
Примечание: можно было последней строкой написать print(i, res)
, ничего бы не изменилось.