Python привлекает тем, что код на нём читается почти как обычный текст: меньше скобок, меньше церемоний, больше смысла на строку. Но за этой простотой стоят несколько решений языка, которые лучше понять сразу — иначе легко словить неожиданное поведение. Разберём базовый синтаксис и систему типов с самого начала.
Отступы — это блоки кода
В большинстве языков блок кода выделяют фигурными скобками. В Python блок задаётся отступом — обычно четыре пробела. Двоеточие в конце строки открывает новый блок, а возврат на прежний уровень отступа его закрывает.
def greet(name):
if name: # двоеточие открывает блок
print(f"Привет, {name}") # этот код внутри if
else:
print("Привет, гость")
print("Готово") # снова уровень функции, вне if/else
Из этого следует простое правило: отступы — не косметика, а синтаксис. Сместил строку на пробел — изменил смысл программы или получил ошибку. Не смешивай пробелы и табы; общепринятый стиль — четыре пробела.
Переменные и динамическая типизация
Переменную не нужно объявлять заранее и указывать её тип — достаточно присвоить значение. Тип определяется в момент присваивания и может меняться по ходу программы. Это и есть динамическая типизация.
x = 42 # сейчас x — целое число
x = "сорок" # а теперь та же переменная ссылается на строку
Важно понимать, что переменная в Python — это не «коробка со значением», а имя, привязанное к объекту. Присваивание не копирует значение, а перенаправляет имя на другой объект. Узнать тип текущего значения можно функцией type:
live example
n = 42
print(type(n)) # <class 'int'>
Run
Running examples is part of paid access. There the same code runs inside the article: editor, run and check next to the paragraph. Three free days →
Динамическая типизация удобна для быстрой разработки, но за ней легко не заметить ошибку: переменная незаметно стала не тем, чем вы ожидали. Поэтому в серьёзных проектах добавляют подсказки типов (об этом — в отдельной статье).
Базовые типы
Минимальный набор, с которого всё начинается:
age = 30 # int — целое число произвольной длины
price = 19.99 # float — число с плавающей точкой
name = "Анна" # str — строка (текст в кавычках)
active = True # bool — логический тип: True или False
nothing = None # None — «значения нет»
Несколько деталей, которые экономят время:
intне имеет фиксированного предела разрядности — большие числа не переполняются, Python расширяет их автоматически.float— это та же двоичная плавающая точка, что и везде, со всеми её сюрпризами:0.1 + 0.2даст0.30000000000000004, а не ровно0.3. Поэтому такие числа никогда не сравнивают через==— только с допуском:math.isclose(a, b)из модуляmath(при сравнении с нулём ему нужен ещёabs_tol). Для денег используют типDecimalиз модуляdecimal.boolна самом деле подвидint:Trueравен1,Falseравен0. ПоэтомуTrue + Trueвернёт2(так делать не стоит, но знать полезно).None— единственное значение типаNoneType, означает «здесь ничего нет». Сравнивают с ним черезis:if value is None.
f-строки: подстановка значений в текст
Самый удобный способ собрать строку из значений — f-строка: буква f перед кавычками включает подстановку выражений в фигурных скобках.
live example
name = "Анна"
age = 30
price = 19.99
print(f"{name}, возраст {age}") # Анна, возраст 30
print(f"Через год будет {age + 1}") # выражение тоже работает
print(f"Цена: {price:.2f}") # форматирование: 19.99
Run
Running examples is part of paid access. There the same code runs inside the article: editor, run and check next to the paragraph. Three free days →
Внутри {} можно писать любое выражение, а после двоеточия — спецификатор формата (например, :.2f — два знака после точки). f-строки читаемее и быстрее, чем старая конкатенация через + или метод format.
Операторы
Арифметика выглядит привычно, но есть пара особенностей:
live example
print(7 / 2) # 3.5 — обычное деление всегда даёт float
print(7 // 2) # 3 — целочисленное деление (отбрасывает дробь)
print(7 % 2) # 1 — остаток от деления
print(2 ** 10) # 1024 — возведение в степень
Run
Running examples is part of paid access. There the same code runs inside the article: editor, run and check next to the paragraph. Three free days →
Сравнения возвращают bool и их можно связывать в цепочку, как в математике:
live example
x = 5
print(0 < x < 10) # True — то же, что 0 < x and x < 10
Run
Running examples is part of paid access. There the same code runs inside the article: editor, run and check next to the paragraph. Three free days →
Логические операторы пишутся словами: and, or, not. А оператор == сравнивает значения, тогда как is — это тот же самый объект в памяти. Для чисел и строк почти всегда нужен ==; is используют только с None.
Управляющие конструкции
Ветвления и циклы тоже опираются на отступы и двоеточие.
score = 75
if score >= 90:
grade = "отлично"
elif score >= 60: # elif — это «else if»
grade = "нормально"
else:
grade = "слабо"
Цикл for в Python перебирает элементы последовательности, а не считает индексы. Чтобы пройтись по диапазону чисел, берут range:
live example
for i in range(3): # 0, 1, 2
print(i)
for letter in "abc": # строку тоже можно перебирать
print(letter)
Run
Running examples is part of paid access. There the same code runs inside the article: editor, run and check next to the paragraph. Three free days →
Цикл while повторяет блок, пока условие истинно. Управляют циклами break (выйти) и continue (перейти к следующей итерации):
live example
n = 0
while True:
n += 1
if n == 3:
continue # пропустить остаток итерации
if n > 5:
break # выйти из цикла
print(n) # 1, 2, 4, 5
Run
Running examples is part of paid access. There the same code runs inside the article: editor, run and check next to the paragraph. Three free days →
Всё в Python — объект
Ключевая идея языка: любое значение — это объект. Число, строка, функция, даже сам тип — у всего есть свой тип, свои методы и идентичность. Это значит, что функцию можно положить в переменную, передать в другую функцию или вернуть из неё.
live example
def shout(text):
return text.upper()
f = shout # функция — обычный объект, кладём в переменную
print(f("привет")) # ПРИВЕТ
Run
Running examples is part of paid access. There the same code runs inside the article: editor, run and check next to the paragraph. Three free days →
Из этого же следует, что у строки или числа есть методы: "abc".upper(), (-5).__abs__(). Единообразие «всё — объект» делает язык предсказуемым: новые сущности ведут себя по тем же правилам, что и встроенные.
Изменяемые и неизменяемые типы
Это одно из самых важных различий, которое стоит усвоить сразу. Объекты бывают неизменяемые (immutable) — их нельзя поменять после создания, и изменяемые (mutable) — их содержимое можно править на месте.
Присваивание не копирует: два имени смотрят на один список, и правка через одно имя видна через другое.
- Неизменяемые:
int,float,bool,str,bytes,tuple,frozenset,None. - Изменяемые:
list,dict,set.
Неизменяемость кортежа неглубокая: сам кортеж не поменять, а список внутри него — можно. t = (1, [2]); t[1].append(3) сработает и даст (1, [2, 3]).
Что значит «нельзя поменять» для строки? Любая операция над ней создаёт новый объект, а старый остаётся нетронутым:
live example
s = "abc"
s2 = s.upper() # создаётся новая строка "ABC"
print(s) # abc — исходная строка не изменилась
Run
Running examples is part of paid access. There the same code runs inside the article: editor, run and check next to the paragraph. Three free days →
А список меняется на месте, и это легко приводит к неожиданностям, когда на один объект ссылаются два имени:
live example
a = [1, 2, 3]
b = a # b и a — это одно имя одного списка
b.append(4)
print(a) # [1, 2, 3, 4] — изменился и a, ведь объект один
Run
Running examples is part of paid access. There the same code runs inside the article: editor, run and check next to the paragraph. Three free days →
Короткая формула: присваивание копирует ссылку, а не объект. Если нужен независимый список, делают копию явно: b = a.copy() или b = list(a).
Отсюда же — частая ловушка новичка: нельзя использовать изменяемый объект как значение по умолчанию у параметра функции (def f(items=[])), потому что этот список создаётся один раз и сохраняется между вызовами. Подробнее об этом — в статье о функциях.
Глубже: деление, округление и сравнение, которые удивляютрасширенное
Несколько мест, где Python ведёт себя не так, как привык человек из других языков, и где ошибка не падает, а тихо даёт не то число.
Целочисленное деление округляет вниз, к минус бесконечности, а не к нулю, и остаток берёт знак делителя:
live example
print(-7 // 2) # -4, а не -3
print(-7 % 2) # 1
Run
Running examples is part of paid access. There the same code runs inside the article: editor, run and check next to the paragraph. Three free days →
round округляет к ближайшему чётному, когда дробь ровно половина: round(2.5) даёт 2,
round(3.5) даёт 4. Для денег это неприемлемо, поэтому там Decimal и quantize с явным
правилом округления:
live example
from decimal import Decimal, ROUND_HALF_UP
print(Decimal("2.675").quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)) # 2.68
Run
Running examples is part of paid access. There the same code runs inside the article: editor, run and check next to the paragraph. Three free days →
Оператор is у маленьких чисел и коротких строк иногда даёт True просто потому, что
интерпретатор держит их в одном экземпляре. На это нельзя рассчитывать: значения
сравнивают через ==, а is оставляют для None.
С версии 3.10 есть match — разбор значения по образцу, который заменяет лесенку
if/elif там, где ветвление идёт по форме данных:
match command.split():
case ["go", direction]:
move(direction)
case ["quit"]:
stop()
case _:
print("не понял")
А с версии 3.12 внутри f-строки можно повторять те же кавычки и писать многострочные
выражения: f"{"вложенные" if ok else "кавычки"}" больше не ошибка.
Глубже: регулярные выражения: re и флагирасширенное
Проверить формат, вытащить число из строки, заменить все вхождения по шаблону: для этого есть модуль re. Шаблон пишут сырой строкой r"...", чтобы обратные слеши не пришлось удваивать. Четыре функции закрывают почти всё: re.search находит первое совпадение где угодно в строке, re.match только в её начале, re.findall возвращает все совпадения списком, re.sub заменяет. Группы в круглых скобках вытаскивают части совпадения, а именованные группы (?P<year>\d{4}) делают это читаемым.
live example
import re
log = "2026-10-05 ERROR order=42 user=Анна; 2026-10-05 error order=43 user=Иван"
pattern = re.compile(r"(?P<level>error) order=(?P<order>\d+)", re.IGNORECASE)
for m in pattern.finditer(log):
print(m.group("level"), m.group("order")) # ERROR 42, error 43
print(re.sub(r"user=\S+", "user=***", log))
Run
Running examples is part of paid access. There the same code runs inside the article: editor, run and check next to the paragraph. Three free days →
Флаг re.IGNORECASE даёт нечувствительность к регистру, re.MULTILINE заставляет ^ и $ работать на каждой строке, re.VERBOSE разрешает пробелы и комментарии внутри длинного шаблона. Шаблон, который используется в цикле или в обработчике, компилируют один раз через re.compile, хотя модуль и сам кеширует последние шаблоны. Две оговорки: match без $ в конце проверяет только начало строки, а не всю её, и шаблоны с вложенными повторениями вроде (a+)+ на неудачном входе работают экспоненциально долго, поэтому на пользовательский ввод их не выпускают.
Коротко
- Блоки кода задаются отступами (4 пробела) и двоеточием, а не скобками — отступ это синтаксис.
- Типизация динамическая: тип привязан к значению, а переменная — это имя-ссылка на объект.
- Базовые типы:
int(без предела разрядности),float(двоичный, неточный для дробей),str,bool(подвидint),None. - f-строки (
f"{value}") — основной способ собирать текст из значений. /всегда даётfloat,//— целочисленное деление;==сравнивает значения,is— идентичность (нужен дляNone).- Всё — объект: функции, типы и числа можно хранить в переменных и передавать.
- Делите типы на неизменяемые (
int,str,tuple) и изменяемые (list,dict,set); присваивание копирует ссылку, а не объект. //округляет вниз,round— к ближайшему чётному; для денегDecimalс явным правилом округления.- Регулярные выражения:
re.search,re.findall,re.sub, сырые строкиr"...", флагиIGNORECASEиMULTILINE, компиляция черезre.compileдля шаблона в цикле.
Что почитать дальше
- Структуры данных Python — списки, словари, множества и кортежи подробно.
- Функции и модули — как объявлять функции, аргументы по умолчанию и организация кода.
- Инструментарий разработчика — окружения, пакеты и проверка типов на практике.