Типы данных в Python — полный гайд для аналитика

Коротко

Python — язык с динамической типизацией: переменная не привязана к типу, тип определяется по значению. Для аналитика это значит удобную работу с данными — не нужно объявлять типы заранее. Но на собеседованиях обязательно спросят про разницу мутабельных и иммутабельных типов, приведение типов и подводные камни.

Числовые типы: int, float, complex

# int — целое число, неограниченная точность
users_count = 4200
big = 10 ** 100  # Python справится

# float — число с плавающей точкой (IEEE 754, 64 бита)
conversion_rate = 0.032
revenue = 1_500_000.50  # подчёркивания для читаемости

# complex — комплексное число (редко нужен аналитику)
z = 3 + 4j

Аналитику важно помнить: float не всегда точен. 0.1 + 0.2 != 0.3 — классика. Для финансовых расчётов лучше decimal.Decimal.

str — строки

name = 'Карьерник'
query = "SELECT * FROM users WHERE status = 'active'"

# f-строки — основной способ форматирования
metric = 'retention'
print(f'Метрика: {metric}, значение: {0.85:.1%}')
# Метрика: retention, значение: 85.0%

# Многострочная строка
sql = """
SELECT user_id, count(*)
FROM events
GROUP BY 1
"""

Строки в Python неизменяемы (immutable). Любая операция вроде .upper() или конкатенации создаёт новый объект.

bool и None

is_active = True
has_premium = False

# bool — подтип int
True + True   # 2
sum([True, False, True, True])  # 3 — удобно для подсчёта

# None — отсутствие значения
result = None
if result is None:
    print('Нет данных')

Сравнение с None всегда через is, не ==. Это частый вопрос на собеседовании.

list — списки

metrics = ['dau', 'wau', 'mau']
metrics.append('retention')     # добавить элемент
metrics[0] = 'dau_unique'       # изменить по индексу

# List comprehension
squares = [x ** 2 for x in range(5)]  # [0, 1, 4, 9, 16]

list — мутабельный, упорядоченный, допускает дубликаты. Основная рабочая коллекция для аналитика. Подробнее — в статье про list comprehension.

tuple — кортежи

point = (10, 20)
rgb = (255, 128, 0)
singleton = (42,)  # запятая обязательна для одного элемента

x, y = point  # распаковка

tuple — неизменяемый. Работает как ключ словаря и элемент множества (если все элементы хешируемы). Быстрее и легче list по памяти. Подробнее — в статье list vs tuple.

dict — словари

user = {'name': 'Анна', 'age': 25, 'city': 'Москва'}

user['role'] = 'analyst'        # добавить
user.get('salary', 0)           # безопасный доступ

# Dict comprehension
{k: v for k, v in user.items() if v != 0}

dict — мутабельный, упорядоченный (с Python 3.7+), ключи уникальны. Поиск по ключу за O(1). Подробнее — в гайде по словарям.

set и frozenset — множества

# set — мутабельное множество
unique_users = {101, 102, 103, 101}  # {101, 102, 103}
unique_users.add(104)

# Операции над множествами
a = {'sql', 'python', 'excel'}
b = {'python', 'tableau', 'sql'}
a & b  # {'sql', 'python'} — пересечение
a | b  # {'sql', 'python', 'excel', 'tableau'} — объединение
a - b  # {'excel'} — разность

# frozenset — неизменяемое множество, можно использовать как ключ dict
fs = frozenset([1, 2, 3])

set — неупорядоченный, без дубликатов. Быстрая проверка in за O(1). Часто используется для дедупликации и операций пересечения/объединения.

Мутабельность — ключевое понятие

Мутабельность определяет, можно ли изменить объект после создания. Это фундаментальная тема на собеседованиях.

Тип Мутабельный Упорядоченный Пример
int Нет 42
float Нет 3.14
str Нет Да 'hello'
bool Нет True
None Нет None
tuple Нет Да (1, 2, 3)
frozenset Нет Нет frozenset({1, 2})
list Да Да [1, 2, 3]
dict Да Да (3.7+) {'a': 1}
set Да Нет {1, 2, 3}

Иммутабельные типы можно хешировать (использовать как ключ dict или элемент set), если все их элементы тоже хешируемы. Мутабельные — нельзя.

Проверка типа: type() и isinstance()

x = [1, 2, 3]

type(x)              # <class 'list'>
type(x) == list      # True

isinstance(x, list)      # True
isinstance(x, (list, tuple))  # True — проверка нескольких типов
isinstance(True, int)    # True — bool подтип int

isinstance() учитывает наследование и предпочтительнее type() в продакшн-коде. Но type() удобнее для дебага.

Приведение типов

# str -> int / float
int('42')         # 42
float('3.14')     # 3.14

# int -> str
str(100)          # '100'

# list <-> tuple <-> set
list((1, 2, 3))   # [1, 2, 3]
tuple([1, 2, 3])  # (1, 2, 3)
set([1, 1, 2])    # {1, 2}

# bool приведение
bool(0)       # False
bool('')      # False
bool([])      # False
bool(None)    # False
bool(1)       # True
bool('text')  # True

Falsy-значения: 0, 0.0, '', [], (), {}, set(), None, False. Всё остальное — truthy. Часто спрашивают на собеседованиях.

Частые ошибки

Мутабельный аргумент по умолчанию. Самый популярный баг Python на собеседованиях:

# Опасно — один и тот же список между вызовами
def add_metric(name, metrics=[]):
    metrics.append(name)
    return metrics

add_metric('dau')     # ['dau']
add_metric('wau')     # ['dau', 'wau'] — сюрприз!

# Правильно
def add_metric(name, metrics=None):
    if metrics is None:
        metrics = []
    metrics.append(name)
    return metrics

Целочисленное деление. В Python 3 / всегда возвращает float, // — целочисленное деление:

7 / 2    # 3.5 (float)
7 // 2   # 3 (int)

Сравнение float. Из-за IEEE 754 нельзя сравнивать float через ==:

0.1 + 0.2 == 0.3        # False
abs(0.1 + 0.2 - 0.3) < 1e-9  # True — правильный подход

Советы для аналитика

  • list — когда порядок важен и коллекция будет меняться (список метрик, результаты запроса)
  • tuple — фиксированная структура: координаты, составной ключ, return нескольких значений
  • set — дедупликация, проверка вхождения, пересечение аудиторий
  • dict — маппинги, конфиги, подсчёт вхождений (Counter)
  • Для табличных данных — pandas DataFrame, но под капотом всё те же базовые типы

Вопросы с собеседований

Какие типы данных есть в Python? — Числовые (int, float, complex), строки (str), логические (bool), None, последовательности (list, tuple), множества (set, frozenset), словари (dict). Плюс bytes и bytearray для бинарных данных.

Что такое мутабельность? Какие типы мутабельные? — Мутабельность — возможность изменить объект после создания. Мутабельные: list, dict, set. Иммутабельные: int, float, str, tuple, frozenset, bool, None. Иммутабельные можно хешировать и использовать как ключи словаря.

Чем is отличается от ==?== сравнивает значения, is — идентичность (один и тот же объект в памяти). is используют для сравнения с None: if x is None.

Что будет: [] == False? А bool([])?[] == False вернёт False — это разные типы, и прямое сравнение не работает. Но bool([]) вернёт False, потому что пустой список — falsy-значение.

Почему 0.1 + 0.2 != 0.3? — Из-за представления float в формате IEEE 754. Десятичные дроби 0.1 и 0.2 не имеют точного двоичного представления, поэтому накапливается погрешность. Для точных вычислений используют decimal.Decimal.

Какая разница между динамической и статической типизацией? — В статической (Java, C++) тип переменной задаётся при объявлении и не меняется. В динамической (Python, JS) переменная может ссылаться на объект любого типа. Python — динамически и сильно типизированный: тип не нужно указывать, но '5' + 3 вызовет TypeError.

Потренировать Python-вопросы на практике можно в тренажёре Карьерника. Подробнее про словари, list comprehension и list vs tuple. Больше примеров вопросов — на отдельной странице.

Открыть тренажёр в Telegram — вопросы по Python, pandas, SQL и аналитике. Бесплатно.

FAQ

Сколько типов данных в Python?

Встроенных — около 15 (int, float, complex, str, bool, NoneType, list, tuple, dict, set, frozenset, bytes, bytearray, memoryview, range). На практике аналитик использует 8-10 из них: int, float, str, bool, None, list, tuple, dict, set.

Python — строго или слабо типизированный?

Строго (strongly typed). Python не выполняет неявное приведение между несовместимыми типами: '5' + 3 вызовет TypeError, а не '53' или 8. Но при этом типизация динамическая — тип определяется в рантайме, а не при компиляции.

Зачем нужны type hints, если Python динамический?

Type hints (def func(x: int) -> str:) не влияют на выполнение — Python их игнорирует в рантайме. Но они помогают IDE, линтерам (mypy) и другим разработчикам понять, какие типы ожидаются. В аналитических пайплайнах type hints снижают количество багов.

Как узнать тип переменной?

type(x) возвращает класс объекта. isinstance(x, int) проверяет с учётом наследования. Для дебага используйте type(), для проверок в коде — isinstance().