Глава 2 — Python для аналитика: «Медведь в архиве I»

Переменные, значения и типы

16 мин
Чему научишься
  • заводить переменные и понимать, что на самом деле делает знак =
  • различать четыре базовых типа: int, float, str, bool
  • спрашивать у значения его тип через type() и преобразовывать типы: int(), float(), str()
  • понимать, почему '1240' + '380' даёт '1240380', а не 1620 — и почему это ошибка первого дня почти каждого аналитика

Имя, ярлык и значение

КВЕРИ распаковал первый ящик чёрного ящика — суточную выгрузку. На экране столбик цифр без единой подписи.

Числа без имён — это шум. Дай им имена, и они станут показаниями. — КВЕРИ

Курсант исследует голограмму, где ярлык перемещается между значениями, а четыре вида капсул показывают базовые типы данных и их преобразование.
Знак «=» не сравнивает, а связывает имя со значением, и от типа значения зависит, что с ним вообще можно сделать.

В прологе ты уже писал orders = 1284. Разберём эту строчку всерьёз, потому что дальше на ней стоит всё.

orders = 1284

Знак = здесь — не равенство из математики. Это команда: «положи значение справа в имя слева». Читается справа налево: сначала Python вычисляет то, что справа, потом привязывает к этому результату имя.

Удобная картинка: значение 1284 лежит где-то в памяти, а ordersярлык, наклеенный на него. Ярлык можно переклеить:

orders = 1284      # ярлык orders указывает на 1284
orders = 1310      # тот же ярлык переехал на 1310; 1284 больше не нужен
print(orders)      # 1310

Отсюда странная на вид, но совершенно обычная строка:

orders = orders + 120   # взять текущее значение orders, прибавить 120, результат снова назвать orders

В математике x = x + 120 бессмыслица. В Python — «пересчитай и перепиши». То же самое короче: orders += 120.

Правила имён. Латинские буквы, цифры и _; начинать с цифры нельзя; регистр важен — orders и Orders это два разных имени. Имя должно объяснять, что внутри: avg_check вместо x, dau_today вместо d1. Через неделю ты не вспомнишь, что такое d1, а КВЕРИ припомнит.

Типичная ошибка №1. Стороны перепутаны:

1284 = orders   # SyntaxError: cannot assign to literal

В показанном здесь простом случае слева от = стоит имя, справа — значение или выражение.

Типичная ошибка №2. Опечатка или другой регистр:

orders = 1284
print(Orders)   # NameError: name 'Orders' is not defined

NameError — самая частая ошибка новичка, и почти всегда это опечатка, заглавная буква или невыполненная ячейка выше.

Переменная — это имя для ячейки памятикодпамять Pythonorders = 1284avg_check = 730revenue = orders * avg_checkorders1284avg_check730revenue937320в третьей строке Python подставляет значения: 1284 × 730имя → значение; знак = означает «положи в ячейку»
Имя переменной связано со значением в памяти, как ярлык. Новое присваивание связывает это имя с другим значением.

Четыре типа, из которых состоит всё

У каждого значения в Python есть тип — он определяет, что с этим значением можно делать. Аналитику на старте хватит четырёх:

ТипЧто этоПримеры из архива
intцелое число1284 заказов, 730 рублей, -41 возврат
floatчисло с дробной частью6.0 процента , 783.33 среднего чека
strтекст (строка)'Мурманск', '2025-03-14', '1240'
boolлогическое: только True или False«день аномальный?»

Спросить тип у любого значения можно функцией type():

type(1284)        # <class 'int'>
type(783.33)      # <class 'float'>
type('Мурманск')  # <class 'str'>
type(True)        # <class 'bool'>

Обрати внимание на третью строку таблицы: '1240' — это строка, хотя внутри кавычек цифры. Кавычки решают всё. 1240 — число, с которым можно делать арифметику; '1240' — текст, который просто выглядит как число.

Арифметика

1240 + 380     # 1620   сложение
1240 - 380     # 860    вычитание
1284 * 730     # 937320 умножение
1240 / 4       # 310.0  деление — ВСЕГДА даёт float, даже если делится нацело
1240 // 400    # 3      целочисленное деление (сколько раз влезло)
1240 % 400     # 40     остаток
2 ** 10        # 1024   возведение в степень

Запомни строчку про /: 10 / 2 — это 5.0, а не 5. Python считает, что деление в общем случае даёт дробь, и не притворяется. Когда нужно целое — оберни результат в int() или используй //.

Сравнения дают bool

1240 > 1000    # True
730 == 640     # False   == это ВОПРОС 'равно ли?', а = это КОМАНДА 'присвой'
730 != 640     # True    не равно
6.0 >= 6.0     # True
'Мурманск' == 'мурманск'   # False — регистр важен, для строк сравнение точное

Результат сравнения — обычное значение типа bool, его можно положить в переменную:

is_big_day = orders > 1200
print(is_big_day)   # True

Это и есть будущие фильтры: в главе 3 pandas будет отбирать строки таблицы ровно такими сравнениями, только сразу для всех строк.

Типичная ошибка №3. Написать = там, где нужен вопрос ==:

(orders = 1284)    # SyntaxError
(orders == 1284)   # так правильно

Почему это первый урок, а не сноска

Вот запись №3 из журнала Л.:

Полдня искала, почему дневная выручка получилась 41-значным числом. Ответ: выгрузка отдала суммы строками, а я их сложила. Python не спорил — он честно склеил мне текст длиной в полкилометра.

Это не курьёз, а норма жизни. CSV-файлы, некоторые выгрузки из BI и ответы API могут отдавать значения строками. В CSV вообще нет типов: там текст, разделённый запятыми. И вот что происходит, если этого не заметить:

a = '1240'   # пришло из CSV — это ТЕКСТ
b = '380'    # и это тоже

a + b        # '1240380'  — не сложение, а склейка (конкатенация)

Для строк + означает «приклей одну к другой». Никакой ошибки не будет — и это самое опасное: отчёт не упадёт, он просто соврёт.

А вот смесь типов Python уже не прощает:

'1240' + 380
# TypeError: can only concatenate str (not "int") to str

Перевод с питоньего: «к строке можно приклеивать только строку, а мне подсунули число». Хорошая новость: такая ошибка громкая, ты её увидишь сразу.

Преобразование типов

int('1240')        # 1240     строка → целое
float('730.5')     # 730.5    строка → дробное
str(1240)          # '1240'   число → строка
int(730.9)         # 730      float → int: дробная часть ОТБРАСЫВАЕТСЯ, а не округляется
round(730.9)       # 731      вот это округление
int('  1240  ')    # 1240     пробелы по краям int() прощает

Чего int() не прощает:

int('730.5')       # ValueError: invalid literal for int() with base 10: '730.5'
int('1 240')       # ValueError — пробел внутри
int('730 ₽')       # ValueError — лишние символы

Лечение первого случая: сначала float, потом intint(float('730.5')) даст 730. Лечение остальных — чистка строки, этим займёмся в следующем уроке.

И последняя ловушка

Строки сравниваются как в словаре — посимвольно, а не по величине:

'9' > '10'     # True  (!) потому что символ '9' идёт после '1'
9 > 10         # False

Если сортировка «по сумме» вдруг ставит 9 ₽ выше 10 000 ₽ — ты сортируешь строки, а не числа. Это классический баг в отчётах, и находится он за две секунды: print(type(значение)).

Правило дознавателя: первое, что делаешь с новыми данными, — смотришь их типы. Не «кажется, там числа», а type() и глазами.

Живая ячейка. Сначала предскажи, что напечатает каждая строка, потом запусти и сверься. Затем поменяй значения и запусти ещё раз.
python · pandas
Практика: напиши код
Строка из суточной выгрузки за 14 марта пришла целиком текстом. Преврати три поля в числа (orders, avg_check, refunds) и посчитай net_revenue — выручку с учётом возвратов: каждый возврат забирает один средний чек.
python · pandas
Практика: напиши код
Ночная проверка DAU. Из мониторинга пришли два текстовых значения. Преврати их в числа, посчитай drop_ratio — какую долю от вчерашнего DAU составляет сегодняшний (просто деление), и подними флаг is_anomaly: True, если сегодня меньше 80% от вчера.
python · pandas
Проверь себя
Из CSV пришли два поля: a = '1240' и b = '380'. Что напечатает print(a + b)?
Проверь себя
Из API пришла сумма заказа как строка: raw = '1250.50'. Что вернёт int(raw)?