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

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

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

JSON, CSV, конфигурация, архивы и SQLite

Преобразуйте табличные данные, проверьте структуру, сохраните JSON и выполните параметризованный SQL-запрос.

Из CSV в проверенный JSON

Предположим, таблица содержит название позиции и количество. CSV подходит для табличного обмена, а JSON — для передачи структурированных данных программе. Между чтением и записью нужен отдельный шаг проверки. DictReader возвращает строки: число не станет целым автоматически. В примере мы проверяем набор колонок, непустое название и неотрицательное количество, а не принимаем любую успешно прочитанную запись. Для более подробной диагностики добавьте номер строки и перечень ошибок, прежде чем сохранять итог.

import csv
import json
from io import StringIO

source = StringIO("name,quantity\nКабель,3\nКлемма,0\n")
reader = csv.DictReader(source)
if reader.fieldnames != ["name", "quantity"]:
    raise ValueError("Ожидаются колонки name и quantity")
records = []
for number, row in enumerate(reader, start=2):
    if set(row) != {"name", "quantity"} or row["name"] is None or row["quantity"] is None:
        raise ValueError(f"Неверное число полей в строке {number}")
    name = row["name"].strip()
    quantity = int(row["quantity"])
    if not name or quantity < 0:
        raise ValueError(f"Некорректная строка {number}")
    records.append({"name": name, "quantity": quantity})
print(json.dumps(records, ensure_ascii=False, sort_keys=True))
[{"name": "Кабель", "quantity": 3}, {"name": "Клемма", "quantity": 0}]

Откройте настоящий CSV с encoding="utf-8" и newline="". Разделитель может быть запятой, точкой с запятой или табуляцией; задавайте delimiter по формату выгрузки. Не разбирайте файл через split(","): кавычки, запятые и переносы внутри поля разрушат таблицу. Для записи DictWriter получает явный список колонок; сначала вызывается writeheader. Сохраняйте исходный экспорт: ошибки строк легче исправлять, когда он не перезаписан преобразованным результатом.

JSON описывает данные, а не любые Python-объекты

json.loads читает JSON из строки; json.load — из открытого файлового объекта. Обратные операции — dumps и dump. JSON содержит объекты, массивы, строки, числа, логические значения и null. Python-кортеж после такого кругового преобразования станет списком; ключи JSON-объекта являются строками. Дата, Decimal и произвольный класс требуют заранее выбранного представления. Например, дату передают ISO-строкой и документируют её значение, а денежную сумму — строкой или целым числом минимальных единиц.

Успешный разбор JSON ещё не подтверждает нужную структуру. Проверьте тип верхнего значения, обязательные поля, диапазоны и версию схемы. В Python bool является подклассом int: проверка isinstance(value, int) примет True как количество. Если это недопустимо, используйте type(value) is int. Не подменяйте проверку assert, поскольку оптимизация может его отключить. Для обмена со строгими системами запрещайте NaN при записи через allow_nan=False; точность чисел также согласуют отдельно.

import json

def read_quantity(text):
    value = json.loads(text)
    if not isinstance(value, dict) or set(value) != {"quantity"}:
        raise ValueError("Нужен объект только с полем quantity")
    quantity = value["quantity"]
    if type(quantity) is not int or quantity < 0:
        raise ValueError("quantity: неотрицательное целое число")
    return quantity

for text in ['{"quantity": 2}', '{"quantity": true}', '[]']:
    try:
        print("Количество:", read_quantity(text))
    except ValueError as error:
        print("Ошибка:", error)
Количество: 2
Ошибка: quantity: неотрицательное целое число
Ошибка: Нужен объект только с полем quantity

Настройки TOML и INI

Модуль tomllib появился в Python 3.11 и читает TOML, но не записывает его. Файл для tomllib.load открывают в двоичном режиме; loads принимает текст. Для небольших настроек это удобно: числа и логические значения сохраняют понятные типы. Запись TOML требует другого инструмента либо собственного ограниченного шаблона. Не называйте сторонний TOML-писатель частью стандартной библиотеки и не генерируйте сложный формат простой склейкой непроверенного пользовательского текста.

import configparser
import tomllib

settings = tomllib.loads('[report]\nlimit = 20\nenabled = true\n')
print("TOML:", settings["report"]["limit"], settings["report"]["enabled"])
ini = configparser.ConfigParser(interpolation=None)
ini.read_string('[report]\nlimit = 20\nenabled = yes\n')
print("INI:", ini.getint("report", "limit"), ini.getboolean("report", "enabled"))
TOML: 20 True
INI: 20 True

INI через configparser хранит значения преимущественно как строки; методы getint и getboolean выполняют явное преобразование. Интерполяция и преобразование регистра имён параметров способны влиять на результат, поэтому настройте их по формату. Настройки не обязательно содержат секреты: пароль лучше получать из предназначенного для этого источника окружения или хранилища. Независимо от формата проверяйте пределы после чтения: число 1000000 синтаксически допустимо, но может оказаться неприемлемым размером пачки.

SQLite: данные отдельно от текста SQL

SQLite хранит таблицы в одном файле и подходит для небольшого локального инструмента. Учебная база :memory: живёт только в соединении и не затрагивает файлы пользователя. Значения передавайте через параметры ?, а не f-строкой SQL. Это сохраняет кавычки внутри данных и отделяет их от команды. Параметрами нельзя подставить произвольное имя таблицы или колонки: такие имена выбирают из заранее разрешённых вариантов. Для серии однотипных вставок используйте executemany, для выборки — явно названные поля.

import sqlite3

connection = sqlite3.connect(":memory:", autocommit=False)
try:
    with connection:
        connection.execute("CREATE TABLE items (name TEXT NOT NULL, quantity INTEGER NOT NULL)")
        connection.executemany("INSERT INTO items VALUES (?, ?)", [("Кабель", 3), ("O'Reilly", 1)])
    rows = connection.execute("SELECT name, quantity FROM items WHERE quantity >= ? ORDER BY name", (1,)).fetchall()
    for name, quantity in rows:
        print(name, quantity)
finally:
    connection.close()
O'Reilly 1
Кабель 3

Начиная с Python 3.12 режим транзакций можно явно задавать через autocommit=False; в Python 3.15 параметры соединения после database передают по имени. Блок with connection подтверждает успешную транзакцию или откатывает её при исключении, но не закрывает соединение. Поэтому закрытие вынесено в finally. Коммит не исправляет ошибки проверки данных и не гарантирует отсутствие конфликтов конкурентного доступа. Сначала проверьте строки, затем выберите осмысленную границу транзакции — например, один завершённый импорт.

Архивируйте свои результаты, осторожно извлекайте чужие

zipfile собирает несколько файлов в ZIP; gzip сжимает поток; TAR сохраняет набор записей и может использовать отдельное сжатие. В ZIP задавайте относительное arcname, чтобы не раскрывать абсолютный путь рабочего компьютера. При получении чужого архива проверяйте количество записей, размер распакованных данных, абсолютные пути, компоненты .. и ссылки. Недостаточно посмотреть размер самого ZIP: маленький архив может распаковаться в очень большой объём. В TAR используйте подходящий фильтр извлечения, не объявляя его полной заменой собственных ограничений.

from io import BytesIO
from zipfile import ZipFile, ZIP_DEFLATED

buffer = BytesIO()
with ZipFile(buffer, "w", compression=ZIP_DEFLATED) as archive:
    archive.writestr("report/result.json", '{"count": 2}\n')
    archive.writestr("README.txt", "Учебный отчёт\n")
with ZipFile(BytesIO(buffer.getvalue())) as archive:
    print("Файлы:", ", ".join(sorted(archive.namelist())))
    print("CRC:", archive.testzip() is None)
Файлы: README.txt, report/result.json
CRC: True

Pickle, Base64 и struct решают разные задачи

pickle может восстанавливать Python-объекты, но загрузка недоверенного pickle способна выполнить код. Для входящих данных используйте формат с явной схемой, а не обещание отправителя «это всего лишь объект». base64 переводит байты в текстовое представление и не шифрует их. struct упаковывает числа в двоичный формат с заданной длиной и порядком байтов; для переносимого протокола эти параметры должны быть частью спецификации. Ни один из этих инструментов не заменяет проверку происхождения и смысла данных.

Практика: отвергните лишнее поле

Сделайте JSON-настройку с единственным полем limit: допустимы целые значения от 1 до 100. Проверьте значение 10, True, пустой объект и объект с дополнительным полем. Правильное решение различает ошибки схемы и ошибки диапазона, завершается успешно для демонстрации и не принимает логическое значение за единицу. Такая маленькая граница защищает последующий расчёт от неожиданного типа.

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

def parse_limit(text):
    data = json.loads(text)
    if not isinstance(data, dict) or set(data) != {"limit"}:
        raise ValueError("схема")
    if type(data["limit"]) is not int or not 1 <= data["limit"] <= 100:
        raise ValueError("диапазон или тип")
    return data["limit"]

for text in ['{"limit": 10}', '{"limit": true}', '{}', '{"limit": 2, "extra": 1}']:
    try:
        print(parse_limit(text))
    except ValueError as error:
        print(error)
10
диапазон или тип
схема
схема

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

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

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

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