Типы данных в Python: полный разбор для новичка
Коротко. Тип данных в Python — это категория, которая определяет, что за значение хранит объект и какие операции с ним можно выполнять. Основных встроенных типов девять: числа int, float и complex, строки str, логический bool, списки list, кортежи tuple, множества set и словари dict, плюс особый тип NoneType для пустого значения. Все типы делятся на изменяемые и неизменяемые — это деление важнее, чем кажется новичку, потому что именно на нем строятся самые частые ошибки.
Зачем новичку разбираться в типах данных
Тип — это не формальность, а набор правил, по которым Python обращается со значением. От типа зависит три вещи: какие операции разрешены, сколько памяти занимает объект и как он себя ведет при изменении.
Проще всего это увидеть на примере плюса. Для чисел он складывает, для строк — склеивает, а для смеси числа и строки просто отказывается работать:
print(2 + 3) # 5
print("2" + "3") # '23'
print("2" + 3) # TypeError
Одна и та же строка кода дает три разных результата, и разница только в типах. Поэтому типы — первое, с чего начинается изучение любого языка, и первое, о чем спрашивают на собеседовании джуна.
Что такое тип данных в Python
В Python все является объектом: число, строка, список, функция и даже сам тип. У каждого объекта есть три характеристики: значение, тип и идентификатор — уникальный номер участка памяти, где объект лежит.
a = 10
print(a) # 10 — значение
print(type(a)) # <class 'int'> — тип
print(id(a)) # 140717895746096 — идентификатор
Переменная в Python — это не коробка со значением, а имя-указатель. Строка a = 10 не кладет десятку в переменную, а создает объект «число 10» в памяти и привязывает к нему имя a. Понимание этой детали снимает половину вопросов о том, почему списки ведут себя странно.
Именно поэтому одна и та же переменная может по очереди указывать на объекты разных типов:
x = 10
print(type(x)) # <class 'int'>
x = "десять"
print(type(x)) # <class 'str'>
Типизация в Python: динамическая и строгая
У Python динамическая и при этом строгая типизация. Два слова, за которыми стоят два разных свойства языка.
Динамическая означает, что тип определяется во время выполнения программы, а не заранее. Указывать тип при объявлении переменной не нужно, и менять его по ходу можно свободно — пример выше это показывает. В языках со статической типизацией, таких как C++, Java или C#, тип задается заранее и меняться не может.
Строгая означает, что Python не делает неявных преобразований и не пытается угадать намерения программиста. Классический пример, на котором сравнивают языки:
result = 1 + "1"
# TypeError: unsupported operand type(s) for +: 'int' and 'str'
JavaScript в такой ситуации молча вернет строку '11'. Python останавливает программу и сообщает об ошибке. На первый взгляд это менее удобно, но в больших проектах строгость экономит часы отладки: программа падает сразу и в понятном месте, а не выдает бессмысленный результат где-то дальше.
Чтобы код заработал, преобразование надо написать явно:
result = 1 + int("1")
print(result) # 2
Какие типы данных есть в Python
Встроенные типы удобно разложить на четыре группы.
Числовые — int (целые), float (с плавающей точкой), complex (комплексные), а также bool, который формально относится к числам.
Текстовый — str (строки).
Коллекции — list (списки), tuple (кортежи), set и frozenset (множества), dict (словари).
Особые — NoneType (пустое значение), bytes и bytearray (двоичные данные), а также файловые объекты, итераторы и генераторы.
Новичку в первую очередь нужны первые три группы плюс None. Разберем их по порядку.
Числа: int, float и complex
int хранит целые числа: положительные, отрицательные и ноль. Важная особенность Python — целые числа не ограничены по размеру. Там, где в C++ или Java переменная переполнится после определенной величины, Python спокойно посчитает число длиной в сотни знаков, пока хватает оперативной памяти.
print(2 ** 200)
# 1606938044258990275541962092341162602522202993782792835301376
float хранит числа с дробной частью. Отличить его от целого можно по точке: 10 — это int, а 10.0 — уже float. Точность у float ограничена, о чем ниже отдельный раздел.
complex хранит комплексные числа вида a + bj, где j — мнимая единица. В обычных задачах он почти не встречается, но нужен в инженерных расчетах и обработке сигналов.
a = 42 # int
b = 3.14 # float
c = 2 + 3j # complex
print(a / 4) # 10.5 — деление всегда дает float
print(a // 4) # 10 — целочисленное деление
print(a % 4) # 2 — остаток от деления
print(a ** 2) # 1764 — возведение в степень
Отдельно стоит знать про интернирование : Python заранее создает объекты для небольших целых чисел от -5 до 256 и переиспользует их. Поэтому две переменные с одинаковым маленьким числом ссылаются на один объект, а с большим — на разные. Это внутренняя оптимизация, но она объясняет неожиданное поведение оператора is, о котором спрашивают на собеседованиях.
Почему 0.1 плюс 0.2 не равно 0.3
Ловушка, на которой спотыкается каждый новичок:
print(0.1 + 0.2) # 0.30000000000000004
print(0.1 + 0.2 == 0.3) # False
Дело не в баге Python, а в устройстве компьютеров. Тип float хранит числа в двоичной системе, а дробь 0.1 в двоичной записи бесконечна — примерно как одна треть в десятичной. Компьютер обрезает ее, и накапливается крошечная погрешность.
Что с этим делать. Для сравнения дробных чисел не используйте знак равенства, а проверяйте, что разница мала:
print(abs(0.1 + 0.2 - 0.3) < 1e-9) # True
А для денег, где ошибка в сотых долях недопустима, берите тип Decimal из стандартного модуля:
from decimal import Decimal
print(Decimal("0.1") + Decimal("0.2")) # 0.3
Это правило стоит запомнить сразу: float для расчетов, Decimal для денег.
Строки: str
Строка — последовательность символов в кавычках. Кавычки могут быть одинарными, двойными или тройными: тройные позволяют записать текст в несколько строк.
name = 'PROWEB'
city = "Ташкент"
text = """Первая строка
Вторая строка"""
К строкам применимы операции последовательностей: обращение по индексу, срезы, длина, склеивание, повторение.
s = "программирование"
print(len(s)) # 16 — длина
print(s[0]) # п — первый символ
print(s[-1]) # е — последний символ
print(s[0:5]) # прогр — срез
print(s[::-1]) # еинавориммаргорп — разворот строки
Строки неизменяемы: заменить символ на месте нельзя, любой метод создает новую строку.
s = "Привет"
s[0] = "п" # TypeError: 'str' object does not support item assignment
s = "п" + s[1:] # так правильно
print(s) # привет
Из-за неизменяемости склеивать строки в цикле через += неэффективно: на каждой итерации создается новый объект. Правильный способ — собрать список и объединить его методом join():
cities = ["Ташкент", "Самарканд", "Бухара"]
print(", ".join(cities))
# Ташкент, Самарканд, Бухара
Самые ходовые методы строк: upper() и lower() меняют регистр, strip() срезает пробелы по краям, replace() заменяет подстроку, find() ищет позицию, split() разбивает строку на список. Подробный разбор последнего есть в отдельной статье блога.
Отдельно стоит f-строка — удобный способ подставить значения переменных в текст:
name = "Азиз"
age = 19
print(f"Меня зовут {name}, мне {age} лет")
# Меня зовут Азиз, мне 19 лет
Логический тип: bool
bool хранит всего два значения: True и False. Он нужен для условий, циклов и любых проверок.
is_student = True
has_paid = False
print(10 > 5) # True
print(type(10 > 5)) # <class 'bool'>
Формально bool — подтип целых чисел: True равен единице, False равен нулю, и их можно складывать. На этом основан удобный прием подсчета:
answers = [True, False, True, True]
print(sum(answers)) # 3 — сколько ответов верных
Важно понимать правдивость значений. В условиях Python приводит к логическому типу любой объект по простому правилу: пустое и нулевое считается ложью, все остальное — истиной.
Ложными считаются: False, 0, 0.0, пустая строка "", пустой список [], пустой кортеж (), пустой словарь {}, пустое множество и None. Все остальные значения истинны.
Благодаря этому вместо длинной проверки длины можно писать коротко:
items = []
if not items:
print("Список пуст")
Списки: list
Список — упорядоченная изменяемая коллекция. В нем могут лежать элементы любых типов, в том числе другие списки, а количество элементов ничем не ограничено.
courses = ["Python", "Frontend", "QA"]
mixed = [1, "два", 3.0, True, [4, 5]]
print(courses[0]) # Python
print(courses[-1]) # QA
print(courses[0:2]) # ['Python', 'Frontend']
Списки меняются на месте — это их главное отличие от строк и кортежей:
courses = ["Python", "Frontend", "QA"]
courses.append("Data Science") # добавить в конец
courses.insert(0, "AI") # вставить по индексу
courses.remove("QA") # удалить по значению
courses.sort() # отсортировать
print(len(courses)) # длина списка
Списки берут, когда набор данных будет меняться: пополняться, сортироваться, фильтроваться. Из минусов — поиск элемента по значению идет перебором, поэтому в очень больших списках проверка «есть ли элемент» работает медленно. Для этой задачи лучше подходят множества.
Кортежи: tuple
Кортеж — тот же список, только неизменяемый. Записывается круглыми скобками.
coordinates = (41.31, 69.28)
print(coordinates[0]) # 41.31
coordinates[0] = 0 # TypeError: 'tuple' object does not support item assignment
Логичный вопрос новичка: зачем нужен урезанный список? У кортежа три практических преимущества.
Первое — защита данных. Если набор значений не должен меняться (координаты, настройки, дни недели), кортеж гарантирует, что никакая функция его случайно не испортит. Второе — кортеж может быть ключом словаря или элементом множества, а список не может, потому что для этого объект обязан быть неизменяемым. Третье — кортежи занимают чуть меньше памяти и работают немного быстрее.
Кортеж из одного элемента требует запятой, иначе Python посчитает скобки обычной группировкой:
not_tuple = (5) # это просто число 5
real_tuple = (5,) # а это кортеж
Множества: set и frozenset
Множество — неупорядоченная коллекция уникальных элементов. Дубликаты в нем исчезают автоматически.
numbers = {1, 2, 2, 3, 3, 3}
print(numbers) # {1, 2, 3}
У множеств две сильные стороны. Первая — мгновенное удаление дубликатов из списка:
values = [1, 2, 1, 3, 2, 1]
print(list(set(values))) # [1, 2, 3]
Вторая — очень быстрая проверка наличия элемента. В списке Python перебирает элементы по очереди, а во множестве считает хеш и попадает в нужное место сразу. На больших объемах разница огромна.
Множества поддерживают операции из школьной математики: объединение, пересечение, разность.
group_a = {"Азиз", "Дилноза", "Тимур"}
group_b = {"Тимур", "Малика"}
print(group_a | group_b) # объединение
print(group_a & group_b) # пересечение: {'Тимур'}
print(group_a - group_b) # разность
Ограничения тоже есть: элементы множества не упорядочены и не имеют индексов, поэтому обратиться к numbers[0] не получится. И хранить в множестве можно только неизменяемые объекты — списки и словари туда положить нельзя.
Отдельно существует frozenset — неизменяемая версия множества. Она нужна, когда множество само должно стать ключом словаря или элементом другого множества.
frozen = frozenset(["a", "b", "c"])
Словари: dict
Словарь хранит пары «ключ — значение». Это самый используемый тип для структурированных данных: карточек товаров, профилей пользователей, настроек, ответов API.
student = {
"name": "Дилноза",
"age": 21,
"course": "Data Science",
"is_active": True
}
print(student["name"]) # Дилноза
student["city"] = "Ташкент" # добавить пару
del student["is_active"] # удалить пару
print(student.get("phone")) # None вместо ошибки
Обращение через квадратные скобки к несуществующему ключу вызывает ошибку KeyError, а метод get() в такой ситуации вернет None. Для данных из внешних источников безопаснее get().
Ключом может быть только неизменяемый объект: строка, число, кортеж. Значением — что угодно, включая списки и другие словари, глубина вложенности не ограничена.
Отдельно стоит развеять устаревшее утверждение, которое до сих пор встречается в статьях: словари в Python неупорядочены. Это перестало быть правдой начиная с версии 3.7 — теперь словарь гарантированно сохраняет порядок добавления ключей.
NoneType: значение «ничего»
None — специальный объект, который обозначает отсутствие значения. Это не ноль, не пустая строка и не False, а именно «ничего».
result = None
print(type(result)) # <class 'NoneType'>
None возвращают функции, которые ничего не возвращают явно, и методы, которые меняют объект на месте. Из-за этого возникает классическая ошибка новичка:
numbers = [3, 1, 2]
numbers = numbers.sort() # ошибка: sort() меняет список и возвращает None
print(numbers) # None
Правильно — вызвать метод отдельно или использовать функцию sorted(), которая возвращает новый список.
Проверять None принято через оператор is, а не через равенство:
if result is None:
print("Значения нет")
Изменяемые и неизменяемые типы
Это деление важнее всех остальных, потому что именно из него растут неочевидные ошибки.
Неизменяемые типы: числа, строки, кортежи, frozenset, None. Их содержимое нельзя поменять после создания — любая операция создает новый объект.
Изменяемые типы: списки, словари, множества. Их можно менять на месте, идентификатор объекта при этом остается прежним.
Увидеть разницу помогает функция id():
number = 10
print(id(number))
number += 5
print(id(number)) # идентификатор изменился — это новый объект
items = [1, 2, 3]
print(id(items))
items.append(4)
print(id(items)) # идентификатор тот же — объект изменился на месте
Две ловушки изменяемых типов
Ловушка первая: копирование, которого не было. Присваивание списка другой переменной не создает копию, а добавляет второе имя тому же объекту.
a = [1, 2, 3]
b = a
b.append(4)
print(a) # [1, 2, 3, 4] — изменился и a
Чтобы получить настоящую копию, используйте срез, метод copy() или конструктор списка:
b = a.copy() # или a[:], или list(a)
Для вложенных списков этого мало — нужен deepcopy из модуля copy, который копирует и внутренние объекты.
Ловушка вторая: изменяемый аргумент по умолчанию. Значение по умолчанию вычисляется один раз при определении функции, а не при каждом вызове. Поэтому список «запоминает» данные между вызовами:
def add_item(item, basket=[]):
basket.append(item)
return basket
print(add_item("хлеб")) # ['хлеб']
print(add_item("молоко")) # ['хлеб', 'молоко'] — сюрприз
Правильный вариант — передавать None и создавать список внутри:
def add_item(item, basket=None):
if basket is None:
basket = []
basket.append(item)
return basket
Как узнать тип данных: type и isinstance
Есть две функции, и они решают разные задачи.
type() возвращает точный тип объекта:
print(type(5)) # <class 'int'>
print(type("текст")) # <class 'str'>
print(type([1, 2])) # <class 'list'>
isinstance() проверяет, принадлежит ли объект указанному типу, и возвращает True или False. Он же понимает наследование и умеет проверять сразу несколько типов:
print(isinstance(5, int)) # True
print(isinstance(5, (int, float))) # True — подходит любой из двух
На практике для проверок берут isinstance(), а type() используют, когда нужно именно посмотреть тип, например при отладке.
Преобразование типов
Python не преобразует типы сам, но дает набор функций, чтобы сделать это явно.
print(int("42")) # 42 — строка в число
print(int(3.9)) # 3 — дробная часть отбрасывается, без округления
print(float("3.14")) # 3.14
print(str(42)) # '42'
print(bool(0)) # False
print(list("abc")) # ['a', 'b', 'c']
print(tuple([1, 2])) # (1, 2)
print(set([1, 1, 2])) # {1, 2}
Чаще всего преобразование нужно после ввода данных: функция input() всегда возвращает строку, даже если пользователь ввел число.
age = input("Ваш возраст: ")
print(age + 1) # TypeError
age = int(input("Ваш возраст: "))
print(age + 1) # работает
Помните, что int() не округляет, а отбрасывает дробную часть: int(3.9) даст 3. Для округления по правилам математики есть функция round().
Преобразование срабатывает не всегда. Если строка не похожа на число, Python выдаст ValueError:
int("сто") # ValueError: invalid literal for int() with base 10: 'сто'
Аннотации типов
С версии 3.5 в Python можно подсказывать типы прямо в коде. Это не меняет поведение программы — интерпретатор аннотации не проверяет, — но делает код понятнее и позволяет редактору находить ошибки до запуска.
def greet(name: str, age: int) -> str:
return f"{name}, вам {age} лет"
price: float = 45000.0
courses: list[str] = ["Python", "QA"]
Запись name: str означает «ожидается строка», а стрелка -> str описывает тип возвращаемого значения. В учебных скриптах без аннотаций легко обойтись, но в командных проектах они стали стандартом, поэтому знать синтаксис стоит с самого начала.
Какой тип выбрать под задачу
- Целое количество, счетчик, возраст — int
- Цена, вес, проценты — float, но для денег Decimal
- Любой текст, ввод пользователя, ответ API до разбора — str
- Флаг «да или нет», результат проверки — bool
- Набор данных, который будет меняться и сортироваться — list
- Фиксированный набор, который менять нельзя, или ключ словаря — tuple
- Уникальные значения и быстрая проверка наличия — set
- Данные с именованными полями, карточки, настройки — dict
Значение, которого пока нет — None
Коротко о главном
Типы данных в Python — это категории, определяющие, что хранит объект и что с ним можно делать. Основных встроенных типов девять: int, float, complex, str, bool, list, tuple, set, dict, плюс особое значение None. Типизация в языке динамическая — тип определяется при выполнении, и строгая — неявных преобразований Python не делает.
Ключевое для практики деление — изменяемые типы против неизменяемых. Списки, словари и множества меняются на месте, из-за чего присваивание не копирует их, а изменяемый аргумент по умолчанию сохраняет состояние между вызовами. Числа, строки и кортежи неизменяемы, поэтому любая операция создает новый объект.
Три вещи, которые стоит запомнить сразу: input() всегда возвращает строку, 0.1 + 0.2 не равно 0.3, а int() не округляет, а отбрасывает дробную часть.
Типы данных — это фундамент, на котором дальше строятся функции, классы и работа с базами. Освоить Python с нуля до уровня реальных проектов можно на курсе Python в PROWEB — 8 месяцев, с 14 лет, с практикой и поддержкой в трудоустройстве. Если вы еще выбираете направление в IT, пройдите бесплатный IT-тест — он подскажет, что вам ближе.
Часто задаваемые вопросы
Какие типы данных есть в Python?
Основные встроенные типы: числа int, float и complex, строки str, логический bool, списки list, кортежи tuple, множества set и frozenset, словари dict. Отдельно стоит NoneType — тип единственного значения None, обозначающего отсутствие данных.
Чем отличаются изменяемые и неизменяемые типы?
Изменяемые объекты можно менять на месте, их идентификатор при этом не меняется. К ним относятся списки, словари и множества. Неизменяемые объекты изменить нельзя — любая операция создает новый объект. Это числа, строки, кортежи, frozenset и None.
Как узнать тип переменной в Python?
Функцией type(), которая возвращает точный тип объекта, или функцией isinstance(), которая проверяет принадлежность к типу и возвращает True или False. Для проверок в коде обычно берут isinstance().
Чем список отличается от кортежа?
Список изменяемый, кортеж — нет. Из-за этого кортеж защищен от случайных изменений, занимает чуть меньше памяти и может быть ключом словаря или элементом множества, а список — не может.
Что такое динамическая типизация?
Это когда тип переменной определяется во время выполнения программы, а не задается заранее. Одной и той же переменной можно последовательно присвоить число, а потом строку — Python не возражает.
Почему 0.1 + 0.2 не равно 0.3?
Тип float хранит числа в двоичной системе, где дробь 0.1 записывается бесконечно и обрезается. Из-за этого накапливается погрешность. Сравнивайте дробные числа через допустимое отклонение, а для денежных расчетов используйте тип Decimal.
Как преобразовать строку в число?
Функциями int() для целых и float() для дробных: int("42") вернет число 42. Если строку нельзя интерпретировать как число, Python выдаст ошибку ValueError.
Что такое None и чем оно отличается от нуля?
None — особое значение, обозначающее отсутствие данных. Это не ноль и не пустая строка, а отдельный объект типа NoneType. Проверять его принято оператором is, а не знаком равенства.
Нужны ли новичку аннотации типов?
Для первых учебных программ не обязательны: Python их не проверяет и на выполнение они не влияют. Но в командной разработке аннотации давно стали стандартом, помогают редактору находить ошибки до запуска, поэтому синтаксис стоит освоить заранее.



