Перейти к основному содержимому

5.02. Работа с типами

Разработчику Архитектору

Работа с типами

Преобразование типов — процесс изменения типа объекта путём интерпретации его значения в контексте другого типа. В Python различают явное (принудительное) и неявное (автоматическое) приведение типов. Явные преобразования осуществляются с помощью встроенных конструкторов типов.

Основные функции преобразования:

  • int(x) — преобразует x в целое число. При преобразовании строки она должна содержать корректное целочисленное представление (возможно с знаком). При преобразовании числа с плавающей точкой отбрасывается дробная часть (усечение к нулю, а не округление). Примеры: int("42") → 42, int(3.9) → 3.
  • float(x) — преобразует x в число с плавающей точкой. Поддерживает строки с десятичной записью, экспоненциальной формой ("1e3"), а также inf, nan. Примеры: float("3.14") → 3.14, float(5) → 5.0.
  • str(x) — возвращает строковое представление объекта. Вызывает метод __str__() объекта. Для встроенных типов результат обычно человеко-читаем. Пример: str(123) → "123", str(True) → "True".
  • bool(x) — возвращает True или False в соответствии с логическим значением объекта. Следует помнить, что в Python большинство объектов имеют «истинное» значение, за исключением None, False, 0, 0.0, 0j, пустых коллекций и строк ("", [], ), и объектов с переопределенным __bool__() или __len__(), возвращающим 0.

bool не является просто «обёрткой» вокруг 0/1. Это полноценный тип, наследуемый от int, где True == 1, False == 0, но это не означает эквивалентности семантики.

Несмотря на динамическую природу Python, в современной разработке активно применяются инструменты статической типизации. Они позволяют выявлять ошибки на этапе анализа кода, улучшать автодополнение в IDE и документировать сигнатуры функций.

Статическая типизация реализуется через аннотации типов (PEP 484) и сторонние анализаторы.

Аннотации типов добавляются с помощью синтаксиса:

def process_data(value: str) -> int:
return len(value)

Они не влияют на выполнение программы, но доступны через __annotations__ и используются анализаторами.

Инструменты статического анализа:

  • mypy — один из первых и наиболее распространённых статических анализаторов. Проверяет соответствие аннотаций типов, включая сложные случаи: объединения (Union), опциональные типы (Optional), дженерики.
  • pyright — анализатор от Microsoft, написанный на TypeScript, интегрирован в VS Code. Отличается высокой скоростью и хорошей поддержкой современных возможностей Python (например, LiteralString, TypeGuard).
  • pyre — разработан Facebook (Meta), ориентирован на производительность при анализе больших проектов. Менее популярен, но эффективен в специфических средах.
  • Pydantic — не является анализатором типов, но активно использует аннотации для валидации данных при создании моделей. Обеспечивает runtime-проверку типов на основе схем, что делает его мощным инструментом для API и конфигураций.

Cтатическая типизация в Python — опциональна и не заменяет тестирование. Она снижает вероятность определённых классов ошибок, но не гарантирует корректность логики.

Работа с числами

Числовые типы в Python включают int, float, complex и decimal.Decimal (из стандартного модуля decimal). Рассмотрим основные операции и особенности.

Арифметические операции:

  • +, -, *, / — обычное деление (всегда возвращает float)
  • // — целочисленное деление (floor division)
  • % — остаток от деления
  • ** — возведение в степень
  • -x, +x — унарные операции

Из особенностей, можно отметить следующее -

  • деление / всегда возвращает float, даже если операнды делятся нацело;
  • целочисленное деление // округляет вниз (к меньшему целому), включая отрицательные числа: -7 // 2 = -4;
  • приоритет операций следует математическим правилам; для группировки используются скобки.

Округление.

Python предоставляет несколько способов округления:

  • round(x) — стандартное округление к ближайшему чётному при равенстве расстояний (банковское округление). Пример: round(2.5) → 2, round(3.5) → 4.
  • math.floor(x) — округление вниз.
  • math.ceil(x) — округление вверх.
  • math.trunc(x) — усечение дробной части (эквивалентно int(x) для положительных).

Модуль decimal.

Для задач, требующих точной арифметики (финансовые расчёты, измерения), рекомендуется использовать тип Decimal из модуля decimal. Он представляет числа в виде десятичных дробей, избегая ошибок двоичного округления (0.1 + 0.2 != 0.3 в float). Точность и режим округления настраиваются через контекст (getcontext()). Операции выполняются медленнее, чем с float, но обеспечивают предсказуемость.

from decimal import Decimal, getcontext
getcontext().prec = 6
result = Decimal('0.1') + Decimal('0.2') # → Decimal('0.3')

Не следует сравнивать float на равенство. Вместо этого используйте math.isclose().

Работа со строками

Строки в Python — неизменяемые последовательности Unicode-символов (тип str). Поддерживают широкий набор операций и методов. Конкатенация и повторение. Конкатенация: s1 + s2, через оператор «+». Повторение: s * n (где n — целое). Не рекомендуется использовать + в цикле для сборки строк — из-за неизменяемости каждый раз создаётся новый объект. Вместо этого следует использовать ''.join(iterable).

Пример конкатенации:

s1 = "Текст"
s2 = " и ещё текст."
print(s1 + s2)

Результат: Текст и ещё текст.

Пример повторения:

s = "Текст"
print(s * 3)

Результат будет «ТекстТекстТекст».

Форматирование строк.

Существует несколько подходов:

  1. f-строки (PEP 498):
name = "Alice"
print(f"Hello, {name}!")

F-строка означает «formatted string». Синтаксис подразумевает добавление буквы f перед текстом. Он позволяет подставлять переменные через фигурные скобки - {имя_переменной}.

Поддерживают выражения, вызовы функций, форматирование (:.2f, !r и т.д.).

  1. Метод .format():
"Hello, {}!".format(name)
"Value: {value:.2f}".format(value=3.1415)

Здесь принцип похож на f-строки, но подразумевает более неудобный синтаксис - нужно расставить в текст фигурные скобки {}, а уже после текста добавить вызов метода format() и в параметрах передать переменную или значение переменной.

  1. % formatting:
"Hello, %s!" % name

% подразумевает подстановку значения с использованием особого форматирования:

  • '%d', '%i', '%u' - десятичное число;
  • '%o' - число в восьмеричной системе счисления;
  • '%x' - число в шестнадцатеричной системе счисления (буквы в нижнем регистре);
  • '%X' - число в шестнадцатеричной системе счисления (буквы в верхнем регистре);
  • '%e' - число с плавающей точкой с экспонентой (экспонента в нижнем регистре);
  • '%E' - число с плавающей точкой с экспонентой (экспонента в верхнем регистре);
  • '%f', '%F' - число с плавающей точкой (обычный формат);
  • '%g' - число с плавающей точкой. с экспонентой (экспонента в нижнем регистре), если она меньше, чем -4 или точности, иначе обычный формат;
  • '%G' - число с плавающей точкой. с экспонентой (экспонента в верхнем регистре), если она меньше, чем -4 или точности, иначе обычный формат;
  • '%c' - символ (строка из одного символа или число - код символа);
  • '%s' - строка;
  • '%%' - знак «%».

Учитывая «замудрённость» подходов, очевидно, что лучше использовать первый метод, f-строки.

Срезы (slicing).

Строки поддерживают доступ по индексу и срезы:

  • s[i] — символ по индексу (от 0 до len(s)-1, отрицательные индексы отсчитываются с конца).
  • s[start:stop:step] — срез. Примеры:
  • s[1:4] — символы с 1 по 3.
  • s[::-1] — строка в обратном порядке.
  • s[::2] — каждый второй символ.
s = "Текст"
print(s[1:4])

Результат будет «екс».

Срезы безопасны: выход за границы не вызывает исключения, возвращается пустая строка или максимально возможный фрагмент.

Основные методы строк:

  • s.upper(), s.lower() — изменение регистра.
  • s.strip([chars]) — удаление пробельных символов (или указанных) с концов.
  • s.split(sep=None) — разбиение на список по разделителю.
  • s.replace(old, new[, count]) — замена подстроки.
  • s.startswith(prefix), s.endswith(suffix) — проверка начала/конца.
  • s.find(sub) — возвращает индекс первого вхождения или -1.
  • s.index(sub) — аналогично find, но вызывает ValueError при отсутствии.
  • s.isalpha(), s.isdigit(), s.isalnum() — проверка содержимого.

Все методы возвращают новую строку, так как строки неизменяемы.

Работа с булевыми значениями

Тип bool — подкласс int, содержащий два значения: True и False. Используется для логических выражений, условий и управления потоком выполнения.

Логические операторы

  • and — логическое И (возвращает последнее истинное или первое ложное значение).
  • or — логическое ИЛИ (возвращает первое истинное или последнее ложное).
  • not — логическое НЕ (возвращает True или False).

Операторы поддерживают ленивую (short-circuit) семантику: второе выражение вычисляется только при необходимости.

x = a and b  # если a — False, b не вычисляется

Сравнения.

Операторы сравнения (==, !=, <, <=, >, >=) возвращают bool.

  • == проверяет равенство значений, is — идентичность объектов.
  • Сравнение разных типов возможно, но может давать неочевидные результаты (например, 1 == True — True, так как bool — подкласс int).
  • Избегайте сравнения float на равенство; используйте math.isclose().

Любой объект может быть интерпретирован в булевом контексте (в if, while, and/or). Пустые или нулевые значения считаются ложными, остальные — истинными.

Работа с датами и временем

Модуль datetime предоставляет средства для работы с датами, временем и интервалами. Основные типы:

  • datetime.datetime — комбинированный объект дата+время.
  • datetime.date — только дата.
  • datetime.time — только время.
  • datetime.timedelta — разница между двумя моментами времени.
  • datetime.timezone — информация о часовом поясе.

Создание объектов:

from datetime import datetime, date, timezone

now = datetime.now() # текущие дата и время
utc_now = datetime.now(timezone.utc)
specific = datetime(2025, 4, 5, 12, 30, 0)
today = date.today()

Форматирование и парсинг:

  • strftime(format) — форматирование в строку.
  • strptime(string, format) — парсинг строки в объект.
dt = datetime(2025, 4, 5)
dt.strftime("%Y-%m-%d") # → "2025-04-05"
datetime.strptime("2025-04-05", "%Y-%m-%d")

strptime чувствителен к формату и выбрасывает ValueError при несоответствии.

Операции с временем:

timedelta позволяет прибавлять/вычитать интервалы:

from datetime import timedelta
tomorrow = now + timedelta(days=1)

Разницу между двумя datetime можно получить как timedelta.

Рекомендуется работать с UTC внутри системы и конвертировать в локальное время только на вывод. timezone.utc — константа для UTC.

Для сложных сценариев (летнее время, правила перехода) используется сторонняя библиотека pytz или встроенный zoneinfo (начиная с Python 3.9).