Python: Урок 2 — Файлы и исключения

Python: Урок 2 — Файлы и исключения.md

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


1. Исключения — что это?

Когда Python встречает ошибку во время выполнения, он выбрасывает исключение и прекращает работу программы:

# Это упадёт с ошибкой ZeroDivisionError
result = 10 / 0

# Это упадёт с ошибкой ValueError
number = int("привет")

# Это упадёт с ошибкой KeyError
data = {"name": "Алекс"}
print(data["age"])

Чтобы программа не падала — используют try / except.


2. Конструкция try / except

try:
    result = 10 / 0
except ZeroDivisionError:
    print("Ошибка: деление на ноль!")

# Программа продолжает работу дальше
print("Программа не упала")

Несколько типов исключений

def safe_convert(value):
    try:
        return int(value)
    except ValueError:
        print(f"Нельзя преобразовать '{value}' в число")
        return None
    except TypeError:
        print("Передан неверный тип данных")
        return None

print(safe_convert("42"))      # 42
print(safe_convert("привет"))  # Нельзя преобразовать...
print(safe_convert(None))      # Передан неверный тип...

3. else и finally

try:
    number = int(input("Введите число: "))
    result = 100 / number
except ValueError:
    print("Это не число!")
except ZeroDivisionError:
    print("На ноль делить нельзя!")
else:
    # Выполняется, если ошибок НЕ было
    print(f"Результат: {result}")
finally:
    # Выполняется ВСЕГДА — с ошибкой или без
    print("Программа завершила работу")

finally незаменим для закрытия файлов, соединений с БД и прочих ресурсов.


4. Получить сообщение об ошибке

try:
    data = {"name": "Алекс"}
    print(data["email"])
except KeyError as e:
    print(f"Ключ не найден: {e}")

# Поймать любое исключение
try:
    result = 1 / 0
except Exception as e:
    print(f"Произошла ошибка: {type(e).__name__}{e}")

5. Создать своё исключение

class AgeError(Exception):
    """Исключение для неверного возраста."""
    pass


def set_age(age):
    if age < 0 or age > 150:
        raise AgeError(f"Недопустимый возраст: {age}")
    return age


try:
    set_age(-5)
except AgeError as e:
    print(f"Ошибка: {e}")

6. Работа с файлами — запись

# Режим "w" — создать / перезаписать файл
with open("notes.txt", "w", encoding="utf-8") as file:
    file.write("Первая строка\n")
    file.write("Вторая строка\n")

# Режим "a" — дописать в конец (append)
with open("notes.txt", "a", encoding="utf-8") as file:
    file.write("Третья строка\n")

Конструкция with open(...) автоматически закрывает файл — даже если произошла ошибка.


7. Работа с файлами — чтение

# Прочитать весь файл целиком
with open("notes.txt", "r", encoding="utf-8") as file:
    content = file.read()
    print(content)

# Прочитать построчно
with open("notes.txt", "r", encoding="utf-8") as file:
    for line in file:
        print(line.strip())  # strip() убирает \n в конце

# Прочитать все строки в список
with open("notes.txt", "r", encoding="utf-8") as file:
    lines = file.readlines()
    print(lines)  # ['Первая строка\n', 'Вторая строка\n', ...]

8. Режимы открытия файла

Режим Описание
"r" Чтение (по умолчанию). Ошибка если файл не найден
"w" Запись. Создаёт файл или перезаписывает
"a" Дозапись в конец файла
"x" Создание. Ошибка если файл уже существует
"rb" Чтение в бинарном режиме (для изображений и др.)
"wb" Запись в бинарном режиме

9. Файл не найден — обработка ошибки

filename = "data.txt"

try:
    with open(filename, "r", encoding="utf-8") as file:
        content = file.read()
        print(content)
except FileNotFoundError:
    print(f"Файл '{filename}' не найден")
except PermissionError:
    print(f"Нет прав для чтения файла '{filename}'")

10. Работа с JSON-файлами

JSON — самый популярный формат для хранения структурированных данных:

import json

# Сохранить словарь в JSON-файл
user = {
    "name": "Алекс",
    "age": 25,
    "skills": ["Python", "SQL", "Git"]
}

with open("user.json", "w", encoding="utf-8") as file:
    json.dump(user, file, ensure_ascii=False, indent=2)

# Прочитать JSON-файл обратно в словарь
with open("user.json", "r", encoding="utf-8") as file:
    loaded_user = json.load(file)

print(loaded_user["name"])    # Алекс
print(loaded_user["skills"])  # ['Python', 'SQL', 'Git']

Содержимое user.json:

{
  "name": "Алекс",
  "age": 25,
  "skills": [
    "Python",
    "SQL",
    "Git"
  ]
}

11. Мини-проект: Записная книжка

Простое приложение для хранения заметок в файле:

import json
import os

NOTES_FILE = "notebook.json"


def load_notes():
    if not os.path.exists(NOTES_FILE):
        return []
    try:
        with open(NOTES_FILE, "r", encoding="utf-8") as f:
            return json.load(f)
    except (json.JSONDecodeError, IOError):
        return []


def save_notes(notes):
    with open(NOTES_FILE, "w", encoding="utf-8") as f:
        json.dump(notes, f, ensure_ascii=False, indent=2)


def add_note(text):
    notes = load_notes()
    notes.append({"id": len(notes) + 1, "text": text})
    save_notes(notes)
    print(f"Заметка добавлена (всего: {len(notes)})")


def show_notes():
    notes = load_notes()
    if not notes:
        print("Заметок пока нет")
        return
    for note in notes:
        print(f"[{note['id']}] {note['text']}")


# Использование
add_note("Изучить Python до конца месяца")
add_note("Прочитать документацию по JSON")
add_note("Сделать пет-проект на FastAPI")
show_notes()

Вывод:

Заметка добавлена (всего: 1)
Заметка добавлена (всего: 2)
Заметка добавлена (всего: 3)
[1] Изучить Python до конца месяца
[2] Прочитать документацию по JSON
[3] Сделать пет-проект на FastAPI

Итоги урока

Тема Ключевые инструменты
Исключения try, except, else, finally
Типы ошибок ValueError, KeyError, FileNotFoundError, ZeroDivisionError
Файлы open(), read(), write(), with
JSON json.load(), json.dump()
Своё исключение class MyError(Exception), raise

Что дальше?

  • Урок 3 — Классы и ООП: class, __init__, наследование
  • Урок 4 — Модули: os, pathlib, datetime, re
  • Урок 5 — Библиотеки: requests, работа с API

💡 Совет: Всегда используйте with open(...) вместо ручного file.close() — это надёжнее и чище.