Перейти к содержимому
Поиск
Разработка

Python: полный мануал с примерами и справочником функций

Полный практический мануал Python: от установки и синтаксиса до файлов, сети, тестов и проектов. 25 глав, справочник функций и методов, упражнения с решениями и 195 проверенных примеров.

Александр Некрасов
Python: практический мануал с кодом, папкой и схемой работы

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

Выберите одну из 25 глав или найдите нужную функцию через поиск. В справочнике собраны все 73 позиции официальной таблицы встроенных функций и типов Python 3.15, а также 161 метод и 12 свойств строк, коллекций и путей. Для каждой позиции есть назначение, важный нюанс и ссылка на первичную документацию.

Код можно копировать и скачивать. 195 самостоятельных примеров проверены запуском на Python 3.15.0; у упражнений есть решения и ожидаемый результат. Новые возможности языка отмечены в тексте, а интерактивные фрагменты и команды установки объяснены отдельно.

Если начинаете с нуля, открывайте главы по порядку. Если решаете конкретную задачу, ищите по-русски или по имени Python: open, str.split, Path.read_text.

Python 3.15.025 главПримеры проверены запуском
Все главы руководства 25

Глава 19 · средний

Тесты, отладка, сообщения и читаемый код

Повторите ошибку, проверьте границы функции и отделите диагностические сообщения от полезного результата.

Проверяйте обещанное поведение

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

import io
import unittest

def quantity(text):
    try:
        value = int(text)
    except ValueError as error:
        raise ValueError("Введите целое число") from error
    if value < 0:
        raise ValueError("Количество не может быть отрицательным")
    return value

class QuantityTests(unittest.TestCase):
    def test_regular(self):
        self.assertEqual(quantity(" 3 "), 3)
    def test_zero(self):
        self.assertEqual(quantity("0"), 0)
    def test_invalid(self):
        for text in ["", "abc", "-1"]:
            with self.subTest(text=text):
                with self.assertRaises(ValueError):
                    quantity(text)

suite = unittest.defaultTestLoader.loadTestsFromTestCase(QuantityTests)
result = unittest.TextTestRunner(stream=io.StringIO()).run(suite)
print("Тестов:", result.testsRun)
print("Успешно:", result.wasSuccessful())
Тестов: 3
Успешно: True

Методы assertEqual и assertRaises принадлежат unittest.TestCase; они формируют понятный отчёт при несовпадении. Это не тот же механизм, что оператор assert языка. Обычный assert подходит для внутренних предположений во время разработки, но может исчезнуть при запуске с -O. Проверка пользовательского ввода должна оставаться явным условием и исключением. Также не помещайте необходимую запись файла или изменение состояния внутрь assert: отключение проверки тогда изменит само поведение программы.

От ошибки к проверке исправления

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

Команда терминала для проекта с тестовыми файлами; путь и структура задаются вашим проектом, поэтому этот блок не является самостоятельным исполняемым примером главы:

python -m unittest discover -s tests -v

Подменяйте границу, а не сам расчёт

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

from unittest.mock import Mock

def sum_report(load_rows):
    return sum(row["quantity"] for row in load_rows("demo"))

source = Mock(return_value=[{"quantity": 2}, {"quantity": 3}])
print("Сумма:", sum_report(source))
source.assert_called_once_with("demo")
print("Вызов источника проверен")
failing = Mock(side_effect=OSError("учебная ошибка"))
try:
    sum_report(failing)
except OSError:
    print("Ошибка источника не потеряна")
Сумма: 5
Вызов источника проверен
Ошибка источника не потеряна

Примеры в документации тоже можно проверить

doctest ищет примеры, оформленные как интерактивный Python-сеанс, в строках документации. Это удобно для короткой функции с устойчивым результатом. Такой пример объясняет использование, но не заменяет набор сценариев unittest: объёмная настройка, временные файлы и ветвление ошибок неудобны внутри docstring. Не используйте случайные числа, адреса объектов и текущую дату в точном ожидаемом выводе. Если порядок данных не имеет смысла, сначала нормализуйте его, а не заставляйте читателя угадывать удачный порядок запуска.

import doctest

def title(text):
    """Очистить учебный заголовок.

    >>> title("  Отчёт  ")
    'Отчёт'
    >>> title("   ")
    'Без названия'
    """
    return text.strip() or "Без названия"

result = doctest.testmod()
print("Примеров:", result.attempted)
print("Ошибок:", result.failed)
Примеров: 2
Ошибок: 0

Читать traceback и останавливаться в нужном месте

Traceback показывает цепочку вызовов и место исключения. Начните с типа ошибки и последнего участка вашего кода, затем проверьте входные значения. breakpoint() включает отладчик согласно настройкам окружения; в обычном случае это pdb. Команды step, next и continue помогают пройти вычисление по шагам. Не оставляйте интерактивную остановку в пакетной задаче: программа будет ждать человека. Для автоматического отчёта об исключении можно использовать logging.exception внутри обработчика и сохранить traceback без ручного копирования.

pprint помогает рассмотреть вложенные значения, а inspect — сигнатуру и устройство объекта. Используйте их для уточнения гипотезы: какой тип пришёл, на каком шаге список изменился, где источник вернул пустое значение. Бессистемные print по всему проекту дают шум и затрудняют повторение ошибки. После исправления уберите временную диагностику или превратите нужные сообщения в управляемый лог. Проверяемый результат должен оставаться доступен без включённого отладчика и без анализа внутренних переменных.

Отдельный канал для состояния программы

Лог рассказывает, что делала программа, а её основной вывод содержит результат для пользователя или следующего инструмента. Уровни DEBUG, INFO, WARNING, ERROR и CRITICAL помогают управлять подробностью. Библиотека обычно получает именованный logger и не перенастраивает корневой журнал приложения при импорте. В примере обработчик явно отправляет сообщения в stdout только ради воспроизводимой демонстрации. В обычном CLI диагностику удобно направить в stderr, чтобы перенаправление stdout сохраняло чистый JSON или CSV без служебных строк.

import logging
import sys

logger = logging.getLogger("manual.quality")
logger.handlers.clear()
logger.propagate = False
logger.setLevel(logging.INFO)
handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
logger.addHandler(handler)
logger.debug("Подробность для отладки")
logger.info("Обработано строк: %d", 3)
logger.warning("Пустая запись пропущена")
INFO: Обработано строк: 3
WARNING: Пустая запись пропущена

Не записывайте в лог настоящие пароли, токены и полные входные документы без необходимости. Для диагностики часто достаточно номера учебной записи, типа ошибки и количества обработанных строк. Вызов с шаблоном logger.info("Строк: %d", count) передаёт значение отдельно и позволяет библиотеке отложить форматирование. Выберите политику для повторяющихся ошибок: тысячи одинаковых сообщений способны скрыть первую полезную причину. Логирование не должно заменять исключение там, где задача после ошибки уже не может вернуть корректный результат.

Предупреждения, docstring и ясное имя

Предупреждение через warnings.warn сообщает о важном, но не обязательно аварийном условии: например, устаревшем API. Фильтр решает, показать, игнорировать или превратить его в исключение; поэтому не используйте warnings для проверки обязательного поля. PEP 8 предлагает договорённости о стиле, а docstring объясняет назначение, аргументы, результат и существенные ограничения функции. Название parse_quantity полезнее do_stuff. Короткие функции и разделение расчёта с эффектами помогают читателю, но искусственное дробление одного простого действия на десяток слоёв мешает пониманию.

Практика: пустая выборка — отдельный сценарий

Функция среднего значения должна отвергать пустую выборку понятным исключением. Напишите два теста: для [2, 4] ожидается 3, для пустого списка — ValueError. Не подставляйте ноль вместо ошибки молча: это изменяет смысл результата. После этого измените первый набор на один элемент и добавьте отдельный тест, чтобы убедиться в выбранном контракте функции.

Посмотреть решение
import io
import unittest

def average(values):
    if not values:
        raise ValueError("Пустая выборка")
    return sum(values) / len(values)

class AverageTests(unittest.TestCase):
    def test_values(self):
        self.assertEqual(average([2, 4]), 3)
    def test_empty(self):
        with self.assertRaises(ValueError):
            average([])
    def test_single(self):
        self.assertEqual(average([5]), 5)

result = unittest.TextTestRunner(stream=io.StringIO()).run(unittest.defaultTestLoader.loadTestsFromTestCase(AverageTests))
print("Тестов:", result.testsRun)
print("Успешно:", result.wasSuccessful())
Тестов: 3
Успешно: True

Примеры и материалы с собой

Архив содержит наши самостоятельные примеры, тестовые данные, ожидаемый результат и README. Указанные команды установки и фрагменты REPL отделены от скриптов, которые проверены запуском.

Сверено с официальной документацией 2026-10-12. Стандартная библиотека и сторонние пакеты различаются; ссылки на источники есть в каждой главе.