Переменная в Python — это имя, которое ссылается на объект в памяти. Тип объекта определяется автоматически в момент присваивания: написал x = 10 — Python создал целое число, написал x = "текст" — создал строку. Это называется динамической типизацией (dynamic typing). Понять, как устроены переменные и типы данных в Python, — значит освоить основу, на которой держится любая программа.
В Python девять основных встроенных типов данных: числовые (int, float, complex), строки (str), логический (bool) и коллекции (list, tuple, dict, set). Отдельно стоит frozenset — иммутабельный вариант множества — и специальное значение None. В этой статье разберём каждый тип с примерами кода, научимся их преобразовывать, разберём мутабельность, область видимости и самые частые ошибки.
Переменная — не контейнер с данными, а имя-ссылка на объект в памяти. Разница принципиальная: одну и ту же ячейку памяти могут «видеть» несколько имён одновременно. Ниже разберём синтаксис создания переменных, правила именования и то, что происходит при смене типа.

Оператор = в Python — это присваивание, а не сравнение (для сравнения используют ==). Присваивание работает справа налево: сначала вычисляется правая часть, потом ссылка связывается с именем слева.
Python поддерживает четыре формы присваивания:
Составные операторы (+=, -=, *=, /=) сокращают запись: x += 1 эквивалентно x = x + 1.
Удалить переменную — оператором del x. После этого объект теряет ссылку и становится кандидатом для сборщика мусора (garbage collector) — механизма, который автоматически освобождает занятую память.
x = 5
a, b = 1, 2
a, b = b, a # обмен значениями
del x # переменная удалена
Имя переменной может содержать буквы, цифры и символ _. Начинаться с цифры нельзя: 2players = 4 — это уже SyntaxError.
Стандарт PEP 8 (официальное руководство по стилю кода Python) задаёт три соглашения:
Нельзя использовать ключевые слова Python в роли имён переменных: if, for, while, class, def, return, import, True, False, None и другие зарезервированные слова. Попытка написать class = «10А» немедленно вызовет SyntaxError.

В Python действуют две независимые характеристики системы типов.
Динамическая типизация: тип переменной определяется в момент выполнения программы (runtime), а не при написании кода. Одно и то же имя может последовательно хранить число, строку и список — это легально:
x = 10 # int
x = «десять» # str
x = [1, 2, 3] # list
Проверить текущий тип — функцией type(x): она вернёт, например, <class ‘int’>.
Строгая типизация: Python не делает неявных преобразований между несовместимыми типами. Попытка «1» + 1 вызовет TypeError. В JavaScript «1» + 1 молча вернуло бы «11» — пример нестрогой типизации. Строгость Python защищает от трудноуловимых ошибок в больших программах.
Когда вы пишете list2 = list1, вы не создаёте новый список — вы создаёте второе имя, указывающее на тот же объект. Значит, list2.append(4) изменит и list1:
list1 = [1, 2, 3]
list2 = list1
list2.append(4)
print(list1) # [1, 2, 3, 4]
Чтобы получить независимую копию, используйте copy.deepcopy() (глубокое копирование) из стандартного модуля copy:
import copy
list2 = copy.deepcopy(list1)
Для простых (не вложенных) списков достаточно list2 = list1[:] или list(list1). Глубокое копирование нужно, когда список содержит другие изменяемые объекты.
Переменные и типы данных в Python неотделимы друг от друга: тип определяет, что можно делать с объектом, как он хранится в памяти и где его можно использовать. В таблице ниже — все основные встроенные типы.
| Тип |
Мутабельность |
Хешируемый |
Синтаксис |
Когда использовать |
|---|---|---|---|---|
| int | Нет | Да | x = 42 | Целые числа, счётчики, индексы |
| float | Нет | Да | x = 3.14 | Дробные числа, измерения |
| complex | Нет | Да | x = 3+4j | Инженерные и научные расчёты |
| str | Нет | Да | x = «текст» | Текст, идентификаторы |
| bool | Нет | Да | x = True | Условия, флаги |
| list | Да | Нет | x = [1, 2] | Упорядоченные изменяемые данные |
| tuple | Нет | Да | x = (1, 2) | Фиксированные наборы данных |
| dict | Да | Нет | x = {«k»: 1} | Структуры ключ-значение, JSON |
| set | Да | Нет | x = {1, 2} | Уникальные элементы |
| frozenset | Нет | Да | x = frozenset({1, 2}) | Иммутабельное множество, ключ dict |
Мутабельные (изменяемые) типы — list, dict, set. Иммутабельные (неизменяемые) — всё остальное. Это разделение определяет, какие типы можно использовать как ключи словаря и элементы множества.
Целые числа (int) в Python не ограничены по размеру — в отличие от C++ или Java, где int занимает ровно 4 байта. Можно хранить сколь угодно большие числа; ограничение — только оперативная память.
Особенность: Python кэширует (интернирует) небольшие целые числа от −5 до 256. В этом диапазоне a = 10; b = 10; a is b вернёт True — оба имени ссылаются на один объект в памяти. За пределами этого диапазона поведение другое.
Операторы: целочисленное деление //, остаток %, возведение в степень **.
Числа с плавающей точкой (float) соответствуют стандарту IEEE 754 (международный стандарт представления вещественных чисел). Разделитель дробной части — точка, не запятая: price = 99.9. Классическая ловушка: 0.1 + 0.2 даёт 0.30000000000000004 из-за двоичного представления. Для денежных расчётов используйте модуль decimal. Встроенная функция round() применяет банковское округление — к ближайшему чётному.
Комплексные числа (complex) записываются с суффиксом j: z = 3+4j. Применяются в инженерных расчётах и обработке сигналов.
a = 10 # int
b = 3.14 # float
c = 2 + 5j # complex
print(type(b)) # <class ‘float’>
Строки (str) в Python иммутабельны: изменить отдельный символ «на месте» нельзя. Для создания строки подходят одинарные ‘текст’, двойные «текст» или тройные кавычки «»»многострочный текст»»». Python работает с Unicode — кириллица, японские иероглифы и эмодзи хранятся без дополнительных усилий.
Срезы позволяют получить подстроку: s[1:3] — символы с индексом 1 и 2; s[-1] — последний символ.
Современный стандарт форматирования — f-строки (f-string), появившиеся в Python 3.6+: f»Привет, {name}! Тебе {age} лет.» Они поддерживают выражения прямо внутри фигурных скобок: f»Квадрат: {x**2}». Старые способы — %-форматирование и метод .format() — работают, но f-строки читаются понятнее и рекомендованы для нового кода.
Конкатенация строк через += в цикле создаёт новый объект на каждом шаге — это медленно при большом количестве итераций. Правильнее: собрать части в список и соединить через «».join(parts).
bool — подтип int: True равно 1, False равно 0. Это значит, что True + True даёт 2 — легальная, хотя и специфическая операция.
Значения, которые Python считает «ложными» (falsy): False, 0, 0.0, None, «», [], {}, (). Всё остальное — «истинное» (truthy).
Распространённое заблуждение: bool(«False») вернёт True. Причина: строка «False» непустая, а непустая строка — truthy. Логический тип обычно создаётся операциями сравнения: is_adult = age >= 18.
Список создаётся в квадратных скобках: fruits = [«яблоко», «банан», «вишня»]. Индексация начинается с 0; отрицательные индексы отсчитываются с конца: fruits[-1] вернёт «вишня».
Внутри список хранит ссылки на объекты. Ключевые операции:
Срезы: fruits[0:2] вернёт [«яблоко», «банан»]; fruits[::2] — каждый второй элемент.
nums = [3, 1, 4, 1, 5]
nums.append(9)
print(nums[0]) # 3
print(nums[-1]) # 9
Кортеж создаётся в круглых скобках: point = (50.45, 30.52). Он иммутабельный: попытка изменить элемент вызовет TypeError. Благодаря этому кортеж быстрее списка для данных, которые не должны меняться.
Распаковка — удобный способ извлечь значения: x, y = (10, 20). Кортеж из одного элемента требует запятой: single = (5,).
Типичные применения: координаты (50.45, 30.52), цвет RGB (255, 128, 0), версия программы (3, 11, 2). Кортеж хешируемый, поэтому его можно использовать как ключ словаря.
Словарь — хеш-таблица (hash table): структура данных, обеспечивающая доступ к значению по ключу за O(1). Ключом может быть только иммутабельный тип — строка, число, кортеж, но не список.
user = {«name»: «Алёша», «age»: 16, «city»: «Москва»}
user[«email»] = «a@mail.ru» # добавить
del user[«city»] # удалить
print(«age» in user) # True
defaultdict из модуля collections задаёт значение по умолчанию для новых ключей — удобно при подсчёте или группировке. Словарь — прямой аналог JSON-объекта: с dict работают большинство веб-API.
Множество хранит только уникальные элементы без порядка. Поиск элемента — O(1), что в разы быстрее списка при большом объёме данных.
tags = {«python», «code», «python»} # {«python», «code»}
Операции над множествами: объединение |, пересечение &, разность -. Быстрая дедупликация списка: unique = set(my_list).
frozenset — иммутабельная версия множества. Поскольку frozenset хешируемый, его можно использовать как ключ словаря dict и как элемент другого множества. Обычный set этого не позволяет: попытка добавить set в другой set вызовет TypeError.
fs = frozenset({1, 2, 3})
d = {fs: «значение»} # работает корректно
Мутабельные типы можно изменить после создания: list, dict, set. Иммутабельные не меняются: int, float, str, bool, tuple, frozenset, None.
Практическое следствие: только иммутабельные типы могут быть ключами словаря dict и элементами множества set. Причина — хешируемость: хеш вычисляется один раз при создании объекта и не должен меняться. Если бы список был ключом, его изменение сломало бы структуру хеш-таблицы.
Ещё одно следствие: когда вы «изменяете» иммутабельный объект, Python создаёт новый объект и переводит ссылку на него. Пример:
s = «hi»
s += «!»
# s теперь указывает на новый объект «hi!», а «hi» остался в памяти
Для мутабельных типов картина другая: lst.append(5) изменяет тот же объект в памяти. Все переменные, указывающие на этот список, увидят изменение — отсюда неочевидное поведение при list2 = list1.
Три функции — print(), input() и type() — нужны с первого урока. Рядом с ними стоит группа функций преобразования типов: int(), float(), str(), bool(). Без них невозможно полноценно работать с вводом данных от пользователя.
print() выводит значения в консоль. По умолчанию несколько аргументов разделяются пробелом (sep=» «) и строка заканчивается переносом (end=»\n»). F-строки предпочтительнее перечисления через запятую: print(f»Возраст: {age}») читается лучше, чем print(«Возраст:», age).
input() всегда возвращает строку (str), даже если пользователь ввёл число. Это частая ловушка для новичков:
age = input(«Введите возраст: «)
print(age + 1) # TypeError: can only concatenate str to str
Решение: age = int(input(«Введите возраст: «)).
type() показывает текущий тип объекта: type(3.14) вернёт <class ‘float’>. Незаменим при отладке, когда непонятно, почему операция падает с ошибкой — сначала проверяй типы, потом ищи причину.
Явное преобразование типов — обязательная часть работы с данными в Python. Таблица ниже показывает неочевидные случаи.
| Функция |
Пример |
Результат |
Ловушка |
|---|---|---|---|
| int() | int(«25») | 25 ✅ | — |
| int() | int(3.99) | 3 ⚠️ | Не округляет, а обрезает |
| int() | int(-1.9) | -1 ⚠️ | Тоже обрезает, не округляет |
| bool() | bool(«False») | True ⚠️ | Непустая строка — truthy |
| bool() | bool(0) | False ✅ | — |
| str() | str(42) + «px» | «42px» ✅ | — |
| float() | float(«3,14») | ValueError ⚠️ | Нужна точка, не запятая |
Шаблон для числового ввода: n = int(input(«Введите число: «)). Для дробных значений (вес, цена): price = float(input(«Введите цену: «)). Если операция падает с TypeError — первым делом проверьте типы через type(), затем добавьте нужное преобразование.

Область видимости (scope) — это часть программы, где переменная существует и доступна по имени.
Глобальная переменная объявлена вне любой функции и видна везде в модуле. Локальная переменная живёт только внутри функции: попытка обратиться к ней снаружи после завершения функции вызовет NameError.
Python использует LEGB-правило — порядок поиска имени:
Если имя не найдено ни на одном уровне — NameError.
Чтобы изменить глобальную переменную внутри функции, используйте ключевое слово global:
count = 0
def increment():
global count
count += 1
increment()
print(count) # 1
Без global Python создаст новую локальную переменную count внутри функции, а глобальная останется нетронутой. Это самая распространённая путаница с областью видимости у начинающих.

Три ошибки встречаются чаще всего на начальном этапе изучения Python.
NameError — обращение к переменной, которая не объявлена или написана с опечаткой:
counetr = 0 # опечатка в имени
print(counter) # NameError: name ‘counter’ is not defined
Проверьте написание и убедитесь, что переменная объявлена до обращения к ней. Python показывает имя, которое не нашёл — это упрощает поиск опечатки.
TypeError — операция над несовместимыми типами:
age = input(«Возраст: «) # age — это str
print(age + 5) # TypeError: can only concatenate str to str
Решение: int(age) + 5 или f-строка f»Вам {age} лет». Правило: если падает TypeError — добавьте явное преобразование через int(), str() или float().
SyntaxError — нарушение правил именования или синтаксиса:
2players = 4 # SyntaxError: имя не может начинаться с цифры
class = «10А» # SyntaxError: class — зарезервированное слово
Python показывает номер строки с ошибкой, но реальная причина нередко строкой выше. При SyntaxError первым делом проверьте имена переменных и скобки.
Статическая и динамическая типизация — ключевое различие между языками программирования. Чтобы понять, чем Python отличается от других, удобно сравнить несколько параметров.
| Параметр |
Python |
C++ |
Java |
JavaScript |
|---|---|---|---|---|
| Типизация | Динамическая | Статическая | Статическая | Динамическая |
| Строгость | Строгая | Строгая | Строгая | Нестрогая |
| Объявление типа | Не нужно | Обязательно | Обязательно | Не нужно |
| Смена типа переменной | Разрешена | Запрещена | Запрещена | Разрешена |
Python и JavaScript — динамически типизированные языки. Но Python строгий: неявных преобразований нет. JavaScript — нестрогий: «5» + 5 молча даст «55». C++ и Java требуют явно объявлять тип (int x = 5;) и не позволяют его менять.
Для новичка Python проще: не нужно думать о типах при объявлении. Строгость при этом защищает от скрытых ошибок в больших проектах.
После уверенного освоения переменных и типов данных в Python логичный следующий шаг — условные конструкции if/elif/else, затем циклы for/while с range() и функции def/return. Вместе они составляют базовый инструментарий для написания реальных программ.
Курс «Программирование: Уверенный старт» охватывает переменные, типы данных и операторы уже в первом модуле — сразу с практикой. Результат первого модуля — рабочий Telegram-бот. Курс занимает 36 часов, проходит онлайн в удобном темпе и не требует предварительного опыта.
Хотите писать код, а не только читать о нём? Узнайте подробнее на странице курса «Программирование: Уверенный старт».
В Python не нужно объявлять тип переменной — он определяется автоматически при присваивании (динамическая типизация). В C++ и Java тип указывается явно: int x = 5. Кроме того, в Python переменная — это имя-ссылка на объект в памяти, а не выделенный блок памяти определённого типа.
Falsy — значения, которые Python воспринимает как False в условии if: False, 0, 0.0, None, «», [], {}, (). Всё остальное — truthy. Распространённая ошибка: if name: не сработает, если name = «» (пустая строка), хотя строка создана. Знание falsy-значений помогает писать лаконичные проверки без явного сравнения с None или 0.
frozenset — иммутабельная версия множества. Главное преимущество: frozenset хешируемый, поэтому его можно использовать как ключ словаря dict и как элемент другого множества. Обычный set этого не позволяет — попытка добавить set в другой set вызовет TypeError.
Функция int() не округляет — она обрезает дробную часть. Любое число с плавающей точкой превращается в целое путём отбрасывания всего после запятой: int(3.99) = 3, int(-1.9) = -1. Для округления используйте round(), для округления вверх — math.ceil() из модуля math.
Функция без явного return возвращает специальное значение None типа NoneType. None — единственный экземпляр этого типа, означает «отсутствие значения». Правильный способ проверки: if result is None: (а не == None). None также является falsy-значением.
Обычное присваивание list2 = list1 создаёт вторую ссылку на тот же объект — изменение list2 изменит и list1. Для независимой копии: поверхностная — list2 = list1[:] или list(list1); глубокая, с вложенными объектами — import copy; list2 = copy.deepcopy(list1).
list хранит элементы по числовому индексу (0, 1, 2…), линейный поиск — O(n). dict хранит пары ключ-значение в хеш-таблице: поиск по ключу — O(1). Ключ должен быть иммутабельным: строка, число, tuple. Выбирайте dict, когда у данных есть смысловые имена: профиль пользователя, настройки, ответ API.
LEGB — порядок, в котором Python ищет имя переменной: Local (внутри функции) → Enclosing (во внешней функции) → Global (уровень модуля) → Built-in (встроенные имена Python). Если имя не найдено ни на одном уровне — NameError. Знание LEGB объясняет, почему локальная переменная «перекрывает» глобальную внутри функции.
Да — благодаря динамической типизации Python. x = 10 (int) → x = «десять» (str) → x = [1, 2, 3] (list) — всё это легально. Переменная не привязана к типу: смена значения другого типа просто перемещает ссылку на новый объект в памяти. Проверить текущий тип: type(x).
Python строго типизирован: он не выполняет неявное преобразование между несовместимыми типами. «Возраст: » + 25 вызовет TypeError. Решение: «Возраст: » + str(25) или f-строка f»Возраст: {25}». В JavaScript «Возраст: » + 25 дало бы «Возраст: 25» — пример нестрогой типизации.