Python с нуля до гуру: полный курс

Курс последовательно проведёт вас от первых шагов в Python до уверенного профессионального уровня. Вы освоите синтаксис, структуры данных, ООП, работу с файлами, тестирование, асинхронность и практики разработки, закрепляя знания на мини-проектах.

1. Старт в Python: установка, синтаксис, базовые типы и ввод-вывод

Старт в Python: установка, синтаксис, базовые типы и ввод-вывод

Зачем эта статья

Эта статья — точка входа в курс Python с нуля до гуру: полный курс. Здесь вы:

  • Установите Python и проверите, что он работает
  • Научитесь запускать код в интерактивном режиме и из файла
  • Разберёте базовый синтаксис: отступы, комментарии, переменные
  • Познакомитесь с основными типами данных
  • Освоите ввод-вывод: print() и input()
  • В следующих статьях мы будем опираться на эти основы: запуск окружения, чтение ошибок, понимание типов и простейший ввод-вывод.

    Установка Python

    Какую версию ставить

    Рекомендуемая ветка — Python 3. В рамках курса ориентируемся на актуальные версии Python 3.

    Официальная страница загрузки:

  • Python Downloads
  • Windows

  • Скачайте установщик с Python Downloads.
  • Запустите установку.
  • Обязательно отметьте галочку Add Python to PATH (очень важно).
  • Завершите установку.
  • Проверка в PowerShell или CMD:

    Если команда не находится, часто помогает вариант:

    macOS

    На macOS может быть установлен системный Python, но для обучения лучше использовать свежую версию.

  • Скачайте установщик с Python Downloads.
  • Установите.
  • Проверка в Terminal:

    Linux

    На многих дистрибутивах Python уже установлен.

    Проверка:

    Если Python не установлен, используйте пакетный менеджер вашей системы.

    Редактор кода и интерпретатор

    Python — интерпретируемый язык: код выполняется программой-интерпретатором python.

    Для написания кода нужен редактор. Подойдут многие, но для старта удобно использовать:

  • Visual Studio Code
  • После установки VS Code поставьте расширение Python от Microsoft.

    !Как Python-код превращается в вывод в терминале

    Первый запуск: интерактивный режим и файл

    Интерактивный режим (REPL)

    REPL позволяет выполнять команды по одной строке. Запуск:

    или на macOS/Linux часто:

    Пример:

    Выход обычно:

  • exit()
  • quit()
  • Запуск из файла

    Создайте файл hello.py:

    Запуск:

    или:

    Базовый синтаксис: что нужно знать сразу

    Отступы и блоки кода

    В Python блоки кода выделяются отступами, а не фигурными скобками.

    Пример:

    Важно:

  • Обычно используют 4 пробела на уровень отступа
  • Нельзя смешивать табы и пробелы внутри одного файла
  • Комментарии

    Однострочный комментарий начинается с #:

    Переменные и имена

    Переменная создаётся присваиванием:

    Правила имён:

  • Можно использовать буквы, цифры и _
  • Имя не должно начинаться с цифры
  • Регистр важен: age и Age — разные имена
  • Инструкции и выражения

  • Выражение — то, что вычисляется в значение: 2 + 2, "a" * 3
  • Инструкция — команда: print(...), if ...:
  • Частые ошибки новичков

  • Пропущено двоеточие после if, for, while, def
  • Неправильный отступ
  • Использование = вместо == в условиях
  • Базовые типы данных

    В Python у каждого значения есть тип. Узнать тип можно функцией type():

    Числа

  • int — целые числа
  • float — числа с дробной частью
  • Логический тип

    bool имеет два значения: True и False.

    Сравнения возвращают bool:

    Строки

    str — текст. Строки можно задавать в кавычках:

    Полезные операции:

    None

    None означает нет значения:

    Это не ноль и не пустая строка — это отдельное значение.

    Коллекции: где хранят много значений

    Для старта важно различать основные контейнеры:

  • list — список (изменяемый)
  • tuple — кортеж (обычно неизменяемый)
  • dict — словарь (ключ → значение)
  • set — множество (уникальные элементы)
  • Примеры:

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

    Ввод и вывод

    Вывод: print()

    print() печатает значения в терминал.

    Можно управлять разделителем и концом строки:

    Форматирование строк: f-строки

    Самый удобный способ подставлять переменные в текст — f-строки:

    Ввод: input()

    input() читает строку из терминала.

    Важный момент: input() всегда возвращает строку.

    Если нужно число — преобразуйте тип:

    Если ввести не число, int(...) вызовет ошибку. Это нормально: позже мы научимся обрабатывать такие ситуации.

    Мини-практика: программа целиком

    Пример программы, которая использует ввод, типы и вывод:

    Как читать ошибки

    Когда Python не может выполнить код, он показывает traceback — сообщение об ошибке.

    Что полезно смотреть в первую очередь:

  • Тип ошибки: например, SyntaxError, TypeError, ValueError
  • Строка файла и номер строки
  • Фрагмент кода, где произошла ошибка
  • Пример типичной ошибки типов:

    age здесь строка, а 1 число — Python не будет складывать их автоматически. Исправление:

    Полезные официальные источники

  • The Python Tutorial
  • Built-in Functions
  • Итоги

    Теперь вы умеете:

  • Установить Python и проверить версию
  • Запускать код в REPL и из .py файла
  • Понимать базовые правила синтаксиса (отступы, комментарии)
  • Отличать основные типы: int, float, bool, str, None, а также базовые коллекции
  • Делать ввод-вывод через input() и print(), использовать f-строки
  • Дальше мы начнём уверенно писать программы: разберём операторы, ветвления и циклы, а затем перейдём к функциям и структурам данных глубже.

    2. Управление логикой: условия, циклы, функции, модули и исключения

    Управление логикой: условия, циклы, функции, модули и исключения

    Зачем эта статья

    В прошлой статье вы научились запускать Python, пользоваться print() и input(), различать базовые типы и понимать простые ошибки. Теперь мы сделаем следующий шаг: научимся управлять логикой программы.

    После этой статьи вы сможете:

  • Принимать решения с помощью if и логических операторов
  • Повторять действия с помощью циклов for и while
  • Оформлять код в функции def, возвращать значения через return
  • Подключать код из других файлов через import и понимать, что такое модуль
  • Обрабатывать ошибки с помощью try/except и осознанно вызывать исключения
  • Официальная справка, к которой полезно возвращаться:

  • The Python Tutorial: Control Flow Tools
  • Errors and Exceptions
  • Modules
  • !Схема помогает увидеть, как программа выбирает ветки, повторяется и обрабатывает ошибки

    Условия

    Зачем нужны условия

    Условие позволяет выполнить код только если проверка истинна.

    Пример из реальной жизни: если пользователь ввёл возраст 18 или больше, открыть доступ.

    Конструкция if/elif/else

    Правила:

  • После if, elif, else ставится двоеточие :
  • Внутри блока обязательно есть отступ (обычно 4 пробела)
  • elif и else необязательны
  • Сравнения

    Часто используют операторы сравнения:

    | Оператор | Значение | Пример | |---|---|---| | == | равно | x == 10 | | != | не равно | x != 10 | | < | меньше | x < 10 | | <= | меньше или равно | x <= 10 | | > | больше | x > 10 | | >= | больше или равно | x >= 10 |

    Важно не путать = и ==:

  • = присваивает значение переменной
  • == сравнивает два значения
  • Логические операторы: and, or, not

    Смысл:

  • A and B истинно, если истинны оба
  • A or B истинно, если истинно хотя бы одно
  • not A инвертирует истинность
  • Истинность (truthiness)

    В условиях можно проверять не только True или False, но и другие значения. Некоторые значения считаются ложными:

  • 0, 0.0
  • "" (пустая строка)
  • [], {}, set() (пустые коллекции)
  • None
  • Пример:

    Такой стиль делает код короче и обычно читабельнее, чем сравнение с пустой строкой.

    Циклы

    Зачем нужны циклы

    Циклы позволяют повторять действия:

  • заданное число раз
  • для каждого элемента коллекции
  • пока выполняется условие
  • Цикл for и range

    for удобно использовать, когда известно, сколько раз повторять действие, или когда вы перебираете элементы.

    range(5) генерирует числа 0, 1, 2, 3, 4.

    Варианты:

    Перебор списка

    Если нужен индекс:

    Цикл while

    while повторяет код, пока условие истинно.

    break и continue

  • break завершает цикл целиком
  • continue переходит к следующей итерации
  • Блок else у циклов

    В Python у циклов есть else: он выполняется, если цикл завершился без break.

    Это может быть удобно для поиска.

    Функции

    Зачем нужны функции

    Функция:

  • убирает повторяющийся код
  • делает программу понятнее
  • позволяет тестировать части программы отдельно
  • Объявление и вызов

    return и возвращаемое значение

    Функция может возвращать значение через return.

    Если return не указан, функция возвращает None.

    Параметры по умолчанию

    Область видимости

    Переменная, созданная внутри функции, обычно не видна снаружи.

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

    Модули и импорт

    Что такое модуль

    Модуль в Python — это обычный файл .py, который можно подключать в другие файлы.

    Это основа структуры реальных проектов: вместо одного большого файла вы разбиваете код по смыслу.

    Импорт стандартной библиотеки

    Python поставляется с большой стандартной библиотекой.

    Пример с модулем math:

    Можно импортировать конкретные имена:

    Можно задавать псевдоним:

    Свой модуль: пример из двух файлов

    Файл utils.py:

    Файл main.py в той же папке:

    __name__ и запуск как скрипт

    Иногда в модуле хотят иметь код, который запускается только при прямом запуске файла, но не при импорте.

    Смысл:

  • если файл запущен напрямую, __name__ равен "__main__"
  • если файл импортирован, __name__ будет именем модуля
  • Исключения

    Зачем нужны исключения

    Исключения помогают корректно реагировать на ошибки во время выполнения.

    Пример из прошлой статьи: int(input(...)) ломается, если пользователь вводит не число. Вместо падения программы можно показать понятное сообщение и попросить ввести ещё раз.

    try/except

    Здесь:

  • try содержит код, который может упасть
  • except ValueError ловит конкретную ошибку преобразования строки в число
  • Несколько except

    else и finally

  • else выполняется, если ошибки не было
  • finally выполняется всегда, даже если была ошибка
  • raise: как явно создать ошибку

    Иногда вы хотите сами остановить выполнение, если входные данные неправильные.

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

    Мини-пример: всё вместе

    Ниже программа использует условия, цикл, функцию и обработку исключений.

    Обратите внимание, как функция read_int() прячет повторяющуюся логику безопасного ввода.

    Итоги

    Теперь в вашем наборе инструментов есть ключевые элементы логики программ:

  • Ветвления if/elif/else, сравнения и логические операторы
  • Циклы for и while, управление break и continue, а также else у цикла
  • Функции def, return, параметры и область видимости
  • Модули и импорт: import, from ... import ..., __name__ == "__main__"
  • Исключения: try/except/else/finally и raise
  • Дальше эти конструкции будут встречаться постоянно: при работе со структурами данных, файлами, сетью, классами и библиотеками. Чем увереннее вы ими владеете, тем быстрее будете расти от новичка к уровню гуру.

    3. Структуры данных и алгоритмическое мышление: коллекции, итераторы, генераторы

    Структуры данных и алгоритмическое мышление: коллекции, итераторы, генераторы

    Зачем эта статья

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

    Эта статья научит вас:

  • Выбирать подходящую коллекцию под задачу и понимать последствия выбора
  • Писать код, который мыслит последовательностями и преобразованиями, а не отдельными переменными
  • Уверенно итерироваться по данным: for, iter(), next()
  • Использовать генераторы и ленивые вычисления для экономии памяти и упрощения пайплайнов обработки
  • Полезные официальные источники:

  • Data Structures
  • Iterator Types
  • Generators
  • Алгоритмическое мышление: как подходить к задаче

    Алгоритмическое мышление в контексте Python — это привычка задавать себе правильные вопросы перед тем, как писать код:

  • Какие данные у меня есть: одиночные значения или много элементов?
  • Важен ли порядок?
  • Нужны ли уникальные элементы?
  • Нужен ли быстрый поиск по ключу?
  • Данные помещаются в память целиком или их лучше обрабатывать потоково?
  • В большинстве задач вы будете строить решение по схеме:

  • Представить данные в виде подходящей структуры (например, список заказов, словарь по id, множество уникальных тегов).
  • Пройти по данным (итерация).
  • Преобразовать, отфильтровать, агрегировать (сумма, минимум/максимум, группировка).
  • Получить результат в удобном виде.
  • Коллекции Python: что выбрать и почему

    Краткая карта выбора

    | Тип | Когда использовать | Порядок | Уникальность | Доступ по индексу/ключу | Изменяемость | |---|---|---|---|---|---| | list | последовательность, которую нужно менять | да | нет | по индексу | да | | tuple | фиксированная последовательность | да | нет | по индексу | нет | | dict | сопоставление ключ → значение | да (сохраняет порядок добавления) | ключи уникальны | по ключу | да | | set | проверка уникальности, быстрые операции над множествами | нет | да | нет | да |

    > Практическое правило: сначала выбирайте структуру данных, а уже потом пишите цикл.

    Списки list

    Список — самая универсальная коллекция для хранения последовательности.

    Создание:

    Базовые операции:

    Перебор:

    Частая ошибка новичков: менять список, по которому вы прямо сейчас идёте циклом for. Обычно лучше создать новый список или идти по копии.

    Кортежи tuple

    Кортеж — это как список, но неизменяемый. Он хорошо подходит, когда данные должны оставаться фиксированными.

    Где полезно:

  • возвращать несколько значений из функции
  • хранить “запись” из нескольких полей, которую нельзя случайно изменить
  • Словари dict

    Словарь хранит пары ключ → значение и позволяет быстро получать значение по ключу.

    Безопасное чтение:

    Перебор словаря:

    Когда dict особенно хорош:

  • быстрый поиск сущности по идентификатору
  • подсчёт частот
  • конфигурации и “настройки”
  • Пример: подсчёт частот слов (упрощённо, без очистки текста):

    Множества set

    Множество хранит только уникальные элементы и отлично подходит для проверок “видели ли мы это раньше?”.

    Пример: убрать дубликаты, сохранив только уникальные значения (порядок при этом не гарантируется):

    Операции над множествами читаются почти как математика:

    Вложенные структуры

    Часто данные бывают “табличными” или “иерархическими”. Тогда коллекции вкладываются друг в друга.

    Пример: список словарей (похоже на строки в таблице):

    Типовая задача: быстро находить пользователя по id. Решение: построить словарь-индекс.

    Здесь появляется важный паттерн: предобработка данных ради удобства и скорости дальнейших операций.

    Итерация: как for работает на самом деле

    Итерируемые объекты и итераторы

    В Python многие объекты являются итерируемыми: по ним можно пройти циклом for.

    Примеры итерируемых:

  • список, кортеж, строка
  • словарь (по умолчанию даёт ключи)
  • множество
  • range(...)
  • Внутри for скрывается протокол итерации:

  • Python вызывает iter(obj) и получает итератор.
  • Затем многократно вызывает next(iterator).
  • Когда элементы заканчиваются, итератор выбрасывает исключение StopIteration, и цикл for завершается.
  • Демонстрация руками:

    Почему это важно:

  • вы понимаете, почему “одноразовые” источники (например, генераторы) нельзя просто так пройти дважды
  • вы можете строить эффективные пайплайны обработки данных
  • !Схема показывает, как for использует iter() и next()

    Полезные инструменты для итерации

    enumerate() добавляет индекс:

    zip() склеивает несколько последовательностей по позициям:

    Важно: zip() останавливается на самой короткой последовательности.

    Выражения-коллекции: читаемо и по делу

    List comprehension

    Генератор списков (list comprehension) — короткий способ построить список.

    Обычный цикл:

    То же самое через comprehension:

    Фильтрация:

    Dict и set comprehensions

    Словарь из списка пользователей:

    Множество уникальных длин слов:

    Когда не стоит использовать comprehensions:

  • если выражение становится слишком длинным и хуже читается
  • если внутри много условий и вложенных циклов
  • В таких случаях обычный for часто понятнее.

    Генераторы: когда список делать не нужно

    Проблема “всё в память”

    Список хранит все элементы сразу. Это удобно, но может быть дорого по памяти, если элементов очень много.

    Генераторы позволяют получать элементы по одному, “на лету”, без построения полной коллекции.

    Генераторное выражение

    Похоже на list comprehension, но в круглых скобках и даёт не список, а ленивую последовательность:

    Ключевой эффект: значения вычисляются только когда они нужны.

    Генераторная функция и yield

    Генератор можно писать как обычную функцию, но вместо return использовать yield.

    Пример: генерация чисел Фибоначчи (первые n значений):

    Что делает yield:

  • “возвращает” очередное значение наружу
  • запоминает состояние функции
  • при следующем запросе продолжает с того места, где остановилась
  • Почему генераторы меняют стиль программирования

    С генераторами удобно строить конвейер обработки:

  • читаем элементы
  • фильтруем
  • преобразуем
  • агрегируем
  • Пример: сумма квадратов чётных чисел (без промежуточных списков):

    Здесь:

  • range(...) не хранит миллион чисел в списке
  • генераторное выражение не строит список квадратов
  • sum(...) забирает значения по одному
  • !Наглядное сравнение хранения всех элементов и вычисления по одному

    Одноразовость итераторов и генераторов

    Список можно обходить сколько угодно:

    Генератор обычно “исчерпывается”:

    Если нужно пройти заново, создайте генератор заново.

    Частые практические паттерны

    Поиск и проверка наличия

  • В списке “есть ли элемент” — можно, но при больших данных может быть медленно.
  • В множестве “есть ли элемент” — обычно значительно быстрее.
  • Пример:

    Идея: если вы много раз проверяете принадлежность, имеет смысл подготовить set.

    Группировка и накопление

    Типичный приём: накапливать результаты в dict.

    Пример: группировка слов по первой букве:

    setdefault(key, default) означает: “если ключа ещё нет, создай с default, затем верни значение”.

    Разделяй “чтение” и “обработку”

    Хорошая привычка, связанная с функциями из предыдущей статьи:

  • одна функция получает/поставляет данные (в том числе генератором)
  • другая функция обрабатывает
  • Пример:

    Это делает код проще для тестирования и расширения.

    Итоги

    Теперь у вас есть фундамент для уверенной работы с данными:

  • Вы знаете ключевые коллекции list, tuple, dict, set и понимаете, когда какую выбирать
  • Вы понимаете, как работает итерация в Python через iter() и next() и почему for настолько универсален
  • Вы умеете использовать enumerate() и zip() для аккуратного обхода данных
  • Вы освоили comprehensions для компактного построения коллекций
  • Вы понимаете генераторы, yield и преимущества ленивых вычислений
  • Дальше эти инструменты станут основой для более “взрослых” тем: работа с файлами, обработка потоков данных, тестирование, классы и проектирование кода.

    4. Профессиональный Python: ООП, dataclasses, typing, тестирование и отладка

    Профессиональный Python: ООП, dataclasses, typing, тестирование и отладка

    Зачем эта статья

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

    Следующий шаг от просто работающего кода к профессиональному коду — это умение:

  • моделировать предметную область с помощью ООП
  • создавать “объекты-данные” с помощью dataclasses
  • явно описывать контракты функций и структур данных через typing
  • защищать поведение программы автоматическими тестами
  • быстро находить причины проблем через отладку и грамотное логирование
  • Эта статья связывает уже изученные темы (функции, модули, исключения, коллекции, итерация) с тем, как пишут поддерживаемые проекты.

    Полезные официальные источники:

  • Python Tutorial: Classes
  • dataclasses — Data Classes
  • typing — Support for type hints
  • unittest — Unit testing framework
  • pdb — The Python Debugger
  • logging — Logging facility for Python
  • !Схема связи класса и объектов (экземпляров) и роли self

    Объектно-ориентированное программирование в Python

    Когда ООП полезно

    ООП особенно помогает, когда у вас есть:

  • сущности с состоянием и поведением (например, Пользователь и его действия)
  • инварианты (правила, которые всегда должны быть верными, например “баланс не может быть отрицательным”)
  • много связанной логики, которую хочется сгруппировать и скрыть детали
  • Если задача простая и “одноразовая”, функция и словарь могут быть лучше. Профессиональный Python — это про умение выбирать, а не про “везде классы”.

    Класс и экземпляр

    Класс — это шаблон.

    Экземпляр (объект) — конкретный “предмет”, созданный по шаблону.

    Пример класса пользователя:

    Что важно понять:

  • __init__ вызывается при создании объекта User("Аня")
  • self — это ссылка на текущий объект
  • self.name — атрибут объекта (хранит состояние)
  • greet — метод объекта (описывает поведение)
  • Атрибуты: объектные и классовые

    Объектные атрибуты принадлежат конкретному экземпляру.

    Классовые атрибуты принадлежат самому классу и общие для всех объектов.

    Практический вывод: не храните “изменяемое общее состояние” (например, список) в атрибуте класса, если вы не уверены, что это именно то, что вам нужно.

    Инкапсуляция и “правильные” объекты

    Инкапсуляция — это идея “прятать детали и давать безопасный интерфейс”. В Python нет жёстких модификаторов доступа как в некоторых языках, но есть соглашения:

  • _name означает “внутреннее поле, не трогайте снаружи без необходимости”
  • __name включает механизм name mangling (полезно редко)
  • Пример: банковский счёт, где нельзя уйти в минус.

    Здесь сочетаются темы из прошлых статей:

  • исключения (raise ValueError) для защиты от неверных данных
  • методы как “операции над состоянием”
  • @property как безопасное чтение значения
  • Наследование и композиция

    Наследование: один класс расширяет другой.

    Это называется переопределение метода.

    Но в прикладном коде очень часто лучше работает композиция: “объект содержит другие объекты” вместо “является другим объектом”.

    Пример композиции: заказ содержит список позиций.

    Композиция хорошо сочетается со структурами данных и генераторами из прошлой статьи: sum(...) спокойно работает с любыми итераторами.

    Полиморфизм: один интерфейс, разные реализации

    Полиморфизм — это когда “разные объекты можно использовать одинаково”, если они поддерживают нужные методы.

    В Python это часто выглядит так: нам не важно, что это за класс, важно, что у объекта есть метод to_dict().

    Это естественно сочетается с протоколами из typing (чуть позже в статье).

    Магические методы: как объекты становятся “питоничными”

    Python позволяет вашим объектам поддерживать встроенные операции через dunder-методы (методы вида __something__).

    Практически самые полезные:

  • __repr__ для отладочного представления
  • __str__ для “красивого” текста
  • __len__ чтобы работал len(obj)
  • __iter__ чтобы объект можно было перебирать в for
  • Пример __repr__ и __str__:

    __repr__ особенно важен профессионально: хороший repr ускоряет отладку и чтение логов.

    dataclasses: быстрые и безопасные классы для данных

    Зачем нужны dataclasses

    Очень часто объект нужен не ради сложного поведения, а ради “упаковки данных”: например, Товар с полями name, price.

    Писать вручную __init__, __repr__, сравнение объектов — скучно и повышает шанс ошибки. Для таких случаев есть модуль dataclasses.

    Базовый пример

    Что произошло:

  • @dataclass автоматически создал __init__
  • автоматически появился удобный __repr__
  • аннотации типов (name: str) становятся и документацией, и основой для инструментов проверки типов
  • Значения по умолчанию и default_factory

    Опасный момент: нельзя делать “пустой список по умолчанию” как items=[] в параметрах, потому что такой список будет общим.

    В dataclasses для этого используют field(default_factory=...).

    frozen, order и slots

    Полезные опции:

  • frozen=True делает объект “как неизменяемый” (похоже на идею кортежа)
  • order=True генерирует методы сравнения (например, можно сортировать)
  • slots=True снижает расход памяти и защищает от случайного добавления новых атрибутов
  • frozen=True хорошо подходит для объектов, которые вы используете как “значение” и не хотите, чтобы оно менялось где-то в глубине программы.

    typing: контракты, читаемость и меньше ошибок

    Что такое аннотации типов и что они не делают

    Аннотации типов в Python:

  • улучшают читаемость кода
  • помогают IDE подсказывать корректные варианты
  • позволяют статическим анализаторам (например, mypy) находить ошибки до запуска
  • Но по умолчанию Python не проверяет типы во время выполнения.

    Официальная база: typing — Support for type hints.

    Аннотации функций

  • width: float и height: float — ожидаемые типы аргументов
  • -> float — тип возвращаемого значения
  • Даже если вы не используете внешние анализаторы, это работает как очень точная документация.

    Типы коллекций

    Современный Python позволяет писать типы коллекций так:

    Если тип получается слишком “общим” (например, object), это сигнал: возможно, вам нужна dataclass или TypedDict.

    Optional, Union и оператор |

    Если значение может отсутствовать, часто используют None.

    Optional[str] означает “str или None”.

    В новых версиях Python часто пишут ещё короче:

    TypedDict: словарь с известными полями

    Если вы получаете данные как словарь (например, из JSON), но поля известны, можно описать структуру.

    Это удобно как промежуточный шаг, когда переход на dataclasses или полноценные модели ещё не сделан.

    Protocol: “тип по поведению”

    Иногда важнее не класс, а наличие методов.

    Это закрепляет идею полиморфизма: любой объект, который умеет to_dict(), подходит.

    Тестирование: как не бояться изменений

    Зачем нужны тесты

    Тесты дают две ключевые вещи:

  • уверенность, что код работает как задумано
  • возможность менять реализацию без страха “сломать незаметно”
  • Профессиональная привычка: как только вы нашли баг — добавьте тест, который его воспроизводит, и только потом чините.

    Что тестировать в первую очередь

    Лучшие кандидаты на тесты:

  • функции с понятным входом и выходом
  • методы, которые реализуют бизнес-правила (например, “нельзя снять больше баланса”)
  • разбор и валидацию данных
  • Сложнее тестировать:

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

    unittest: базовый пример

    unittest — стандартный фреймворк тестирования в Python.

    Полезные идеи:

  • тесты — это обычный код
  • имена тестов должны объяснять сценарий
  • используйте несколько маленьких тестов вместо одного большого
  • Если хотите более лаконичный стиль тестов, посмотрите pytest, но даже с unittest можно писать отличные тесты.

    !Цикл “тест → исправление → рефакторинг” для безопасной разработки

    Отладка и диагностика: как быстро находить причину проблемы

    Чтение traceback

    Вы уже встречали traceback в предыдущих статьях. Профессиональный минимум:

  • читать снизу вверх: внизу обычно причина и тип ошибки
  • смотреть файл и номер строки
  • различать TypeError, ValueError, KeyError, AttributeError и понимать типовые причины
  • breakpoint и pdb

    Самый простой способ “остановить мир” и посмотреть значения:

    В отладчике можно:

  • печатать значения переменных
  • выполнять выражения
  • шагать по строкам
  • Документация: pdb — The Python Debugger.

    print против logging

    print() хорош для обучения и быстрых экспериментов.

    Но в реальных проектах лучше logging, потому что:

  • можно настраивать уровни (DEBUG, INFO, WARNING, ERROR)
  • можно писать в файл
  • можно отключать подробные логи без изменения кода
  • Минимальный пример:

    Документация: logging — Logging facility for Python.

    Assertions: быстрые проверки здравого смысла

    assert полезен как внутренняя проверка предположений разработчика.

    Важно:

  • assert не заменяет обработку пользовательского ввода
  • assert можно отключить в некоторых режимах запуска Python, поэтому не используйте его как единственную защиту для критически важной валидации
  • Как собрать всё в один стиль: небольшой пример

    Ниже пример, где сочетаются dataclass, typing, исключения и тестируемая логика.

    Почему это профессионально “в правильную сторону”:

  • данные описаны явно (Item)
  • бизнес-правило оформлено исключением
  • функция total легко тестируется, потому что не читает input() и не печатает print()
  • Итоги

    Теперь у вас есть инструменты, которые отличают учебный код от кода, с которым удобно жить в проекте:

  • ООП: классы, методы, инкапсуляция, наследование и композиция, магические методы
  • dataclasses: быстрые классы данных с безопасными значениями по умолчанию
  • typing: аннотации типов для функций и структур данных, Optional, TypedDict, Protocol
  • тестирование: базовый подход и старт с unittest (и понимание, зачем это нужно)
  • отладка: traceback, breakpoint()/pdb, logging, разумные assert
  • Дальше эти темы станут фундаментом для “взрослых” разделов: работа с файлами и форматами данных, сетевые запросы, асинхронность, проектирование модулей и пакетов, работа с внешними библиотеками и построение приложений.

    5. Продвинутые темы и практика: файлы, сети, asyncio, базы данных, проекты и деплой

    Продвинутые темы и практика: файлы, сети, asyncio, базы данных, проекты и деплой

    Зачем эта статья

    Ранее вы научились писать программы на Python, управлять логикой (условия, циклы, функции), работать со структурами данных, использовать ООП, dataclasses, typing, тестирование и отладку. Теперь мы переходим к темам, которые превращают “учебный код” в “код, который решает реальные задачи”:

  • чтение и запись файлов, работа с форматами данных
  • сетевые запросы и базовая работа с HTTP
  • асинхронность через asyncio для задач ввода-вывода
  • базы данных на примере SQLite
  • сборка проекта: структура, конфигурация, логи, тесты
  • практический деплой: окружение, зависимости, запуск
  • Ключевая идея: вы будете писать программы, которые взаимодействуют с миром вокруг (файлы, сеть, БД), а значит ошибки ввода-вывода, таймауты и “непредсказуемые данные” станут нормой. Здесь особенно важны навыки из прошлых статей: исключения, типизация, тестирование, отладка, проектирование.

    Полезные официальные источники:

  • pathlib — Object-oriented filesystem paths
  • open() — Built-in Functions
  • json — JSON encoder and decoder
  • csv — CSV File Reading and Writing
  • urllib.request — Extensible library for opening URLs
  • asyncio — Asynchronous I/O
  • sqlite3 — DB-API 2.0 interface for SQLite databases
  • venv — Creation of virtual environments
  • logging — Logging facility for Python
  • !Карта, как файлы/сеть/БД соединяются в реальном приложении

    Файлы и форматы данных

    Пути и директории: pathlib

    В учебных примерах часто пишут строки путей, но в проектах удобнее использовать pathlib.Path: он кроссплатформенный и читаемый.

    Практические советы:

  • храните пути как Path, а не как str
  • создавайте директории заранее: path.mkdir(parents=True, exist_ok=True)
  • Контекстный менеджер with и кодировки

    Главное правило работы с файлами: открывайте файл через with. Тогда файл будет закрыт автоматически, даже если внутри блока произойдёт ошибка.

    Ключевые параметры open():

  • режим: "r", "w", "a", "rb", "wb"
  • encoding="utf-8" для текста (особенно важно на Windows)
  • Текст построчно и большие файлы

    Если файл большой, не читайте его целиком через read(). Идите построчно:

    Так вы не загружаете весь файл в память.

    JSON: обмен данными и конфигурации

    JSON часто используют для:

  • обмена данными с API
  • хранения настроек
  • простых “дампов” структур
  • В Python для этого есть модуль json.

    Запись структуры в файл:

    Чтение JSON из файла:

    Типичная проблема: JSON может быть “не таким, как вы ждёте”. Тогда полезны исключения и валидация.

    CSV: табличные данные

    CSV подходит для “простых таблиц”: экспорт из Excel, выгрузки, отчёты. В Python есть модуль csv.

    Запись:

    Чтение:

    bytes и бинарные файлы

    Если вы работаете с изображениями, архивами или любыми “не текстовыми” данными, используйте бинарные режимы "rb" и "wb".

    Сеть: HTTP-запросы и ошибки ввода-вывода

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

    В стандартной библиотеке есть urllib.request.

    Почему здесь важно помнить прошлые темы:

  • сеть может “упасть”, поэтому нужен try/except
  • входные данные могут быть неожиданными, поэтому нужен аккуратный парсинг
  • Пример с обработкой ошибок:

    Практическое правило: всегда задавайте timeout для сетевых операций, иначе программа может “висеть” слишком долго.

    Асинхронность: asyncio для задач ввода-вывода

    Что такое блокирующий ввод-вывод

    Операции вроде “прочитать из сети” или “прочитать с диска” часто ждут внешнего ресурса. Если код написан синхронно, то в это время:

  • поток занят ожиданием
  • программа не может эффективно делать другую работу
  • Асинхронность позволяет выполнять много операций ввода-вывода “как бы параллельно” в одном потоке, переключаясь между задачами в моменты ожидания.

    Базовые понятия: async, await, корутина

  • корутина: функция, объявленная через async def
  • await: “подожди результат асинхронной операции, но дай циклу событий заняться другими задачами”
  • цикл событий: “диспетчер”, который планирует выполнение корутин
  • Минимальный пример:

    !Как event loop переключает задачи при ожидании

    Параллельный запуск задач: create_task и gather

    Если у вас много независимых операций, их можно запустить и дождаться вместе.

    Важно:

  • gather возвращает результаты в порядке задач, а не в порядке завершения
  • если корутина делает “обычную блокирующую работу” (например, синхронный HTTP-запрос), она будет блокировать весь event loop
  • Как подружить asyncio и блокирующие функции

    Если у вас есть блокирующая функция, но вы хотите использовать её в асинхронном коде, можно вынести её в отдельный поток через asyncio.to_thread().

    Это компромисс: вы всё ещё используете синхронную библиотеку, но не блокируете event loop.

    Базы данных: SQLite через sqlite3

    SQLite хорош для обучения и небольших проектов:

  • это файл на диске
  • не нужен отдельный сервер
  • поддерживает SQL и транзакции
  • Создание таблицы, вставка и чтение

    Что важно здесь заметить:

  • sqlite3.connect(...) открывает соединение
  • with ... as con автоматически делает commit при успехе и rollback при ошибке
  • ? в запросе и кортеж параметров защищают от SQL-инъекций и ошибок экранирования
  • Частая ошибка: конкатенация строк в SQL

    Неправильно:

    Правильно:

    Мини-репозиторий: слой доступа к данным

    Чтобы код тестировался и читался лучше, выносите SQL в отдельные функции.

    Так проще писать тесты: вы тестируете “чистые функции”, а не всё приложение целиком.

    Проекты: структура, конфигурация, качество

    Базовая структура проекта

    Один файл main.py подходит для обучения, но в проекте быстро появляется необходимость разнести код.

    Минимально практичная структура:

    Идея:

  • src/my_app — ваш пакет (код приложения)
  • tests — тесты
  • pyproject.toml — место для настройки сборки и инструментов
  • Конфигурация: не зашивайте настройки в код

    Вместо “жёстких” значений в коде используйте:

  • переменные окружения
  • аргументы командной строки
  • Пример чтения переменной окружения:

    Пример аргументов командной строки через argparse:

    Логирование вместо print

    В проектах вам важно управлять “шумом” и направлением вывода. Используйте logging.

    Практическое правило:

  • бизнес-результат показывайте пользователю
  • детали диагностики пишите в лог
  • Связь с typing и тестированием

    Профессиональная связка выглядит так:

  • функции принимают параметры и возвращают значения, а не читают input() внутри
  • типы помогают понять контракт
  • тесты фиксируют поведение
  • Это особенно важно для кода работы с файлами, сетью и БД: они “хрупкие”, и тесты помогают смело улучшать реализацию.

    Деплой: как запускать проект “не только на своём компьютере”

    Виртуальное окружение

    Виртуальное окружение изолирует зависимости проекта от системного Python.

    Создание:

    Активация:

  • Windows PowerShell:
  • macOS/Linux:
  • После этого python и pip относятся к окружению.

    Зависимости: фиксируйте версии

    Минимальная практика:

  • установили библиотеки
  • зафиксировали зависимости
  • Профессиональнее часто используют pyproject.toml, но даже requirements.txt уже даёт воспроизводимость.

    Точка входа и режим запуска

    Хорошая практика — иметь явную точку входа:

    Это связывает тему модулей из прошлых статей с реальным запуском приложения.

    Мини-чеклист перед “передачей” проекта

  • есть README с командами запуска
  • проект запускается в чистом окружении
  • настройки вынесены из кода (хотя бы частично)
  • есть логи и понятные сообщения об ошибках
  • есть базовые тесты для ключевой логики
  • Итоги

    Теперь у вас есть инструменты, которые чаще всего отличают “просто скрипт” от “небольшого приложения”:

  • файлы и форматы: pathlib, open, JSON, CSV, bytes
  • сеть: HTTP-запросы, таймауты, обработка ошибок
  • асинхронность: asyncio, async/await, gather, запуск блокирующего кода через to_thread
  • базы данных: SQLite, транзакции, параметризованные запросы
  • проектный подход: структура, конфигурация, logging, связь с тестами и типами
  • деплой-минимум: venv, фиксация зависимостей, понятная точка входа