Теория
Почему без файла не обойтись
Пока программа запущена, список хранится в памяти. Закроем терминал — и все дела исчезнут. Чтобы список действительно пригодился, будем записывать его после каждого изменения, а при новом запуске — читать обратно из файла.
JSON подходит без дополнительных преобразований: он умеет хранить списки, словари, строки, числа и логические значения. Стандартный модуль json запишет наши объекты Python в текст, а потом восстановит их.
import json with open("tasks.json", "w", encoding="utf-8") as file: json.dump(tasks, file, ensure_ascii=False, indent=2)Что делать, если файла ещё нет
При самом первом запуске файла tasks.json ещё нет — и это нормально. Перехватим только FileNotFoundError и начнём с пустого списка. Другие ошибки не прячем: если код сломан, нам всё ещё нужен traceback.
def load_tasks(): try: with open("tasks.json", "r", encoding="utf-8") as file: return json.load(file) except FileNotFoundError: return []- В первый раз load_tasks не находит файл и возвращает пустой список.
- После добавления дела save_tasks создаёт tasks.json.
- При следующем запуске json.load читает сохранённый список.
- Команда list показывает прежнее дело — вводить его заново не нужно.
Не выдаём уже занятый номер
После перезапуска нельзя снова ставить next_id = 1: такой номер уже может быть в файле. Найдём самый большой сохранённый id и прибавим единицу. Для пустого списка зададим default=0, поэтому первым номером снова станет 1.
next_id = max((task["id"] for task in tasks), default=0) + 1Собираем версию с сохранением
Теперь save_tasks вызывается после успешного добавления, отметки, редактирования или удаления. Команда list ничего не меняет, поэтому записывать файл после неё незачем.
import json FILE_NAME = "tasks.json" def load_tasks(): try: with open(FILE_NAME, "r", encoding="utf-8") as file: return json.load(file) except FileNotFoundError: return [] def save_tasks(tasks): with open(FILE_NAME, "w", encoding="utf-8") as file: json.dump(tasks, file, ensure_ascii=False, indent=2) tasks = load_tasks()next_id = max((task["id"] for task in tasks), default=0) + 1 def find_task(task_id): for task in tasks: if task["id"] == task_id: return task return None def show_tasks(): if not tasks: print("Список пока пуст") return for task in tasks: mark = "x" if task["done"] else " " print(f'[{mark}] {task["id"]}. {task["title"]}') def add_task(): global next_id title = input("Новое дело: ").strip() if not title: print("Название не может быть пустым") return tasks.append({"id": next_id, "title": title, "done": False}) next_id += 1 save_tasks(tasks) def complete_task(): task = find_task(int(input("Номер дела: "))) if task is None: print("Дело не найдено") return task["done"] = True save_tasks(tasks) def edit_task(): task = find_task(int(input("Номер дела: "))) if task is None: print("Дело не найдено") return title = input("Новый текст: ").strip() if title: task["title"] = title save_tasks(tasks) def delete_task(): task = find_task(int(input("Номер дела: "))) if task is None: print("Дело не найдено") return tasks.remove(task) save_tasks(tasks) while True: command = input("Команда: ").strip().lower() if command == "list": show_tasks() elif command == "add": add_task() elif command == "done": complete_task() elif command == "edit": edit_task() elif command == "delete": delete_task() elif command == "exit": break else: print("Неизвестная команда")- Удалите старый тестовый файл. Первый запуск должен начаться с пустого списка.
- Добавьте и отметьте дело. Откройте tasks.json и найдите оба значения.
- Запустите программу снова. Список и отметка должны восстановиться.
- Добавьте новое дело. Его id должен быть больше всех сохранённых.
Практика
Какой модуль работает с JSON
Стандартный модуль json предоставляет функции load и dump.
Как записать список в JSON
json.dump(tasks, file, ...) сериализует список и записывает JSON в файл.
Как прочитать список из JSON
json.load(file) читает JSON и восстанавливает список словарей.
Что происходит при первом запуске
Отсутствующий файл вызывает FileNotFoundError; функция возвращает пустой список.
Продолжаем нумерацию после перезапуска
Максимальный сохранённый id равен 5, поэтому следующий равен 6.
Итог
Теперь программу можно закрыть и открыть снова: дела, отметки и номера восстановятся из файла.
В последнем уроке проверим неприятные случаи: слово вместо номера, неизвестный id и повреждённый JSON. Затем пройдём весь сценарий так, как его проходит обычный пользователь.
Прогресс
0 / 5Вы ещё не решали задания