Урок курса
Запись в текстовый файл
Python для новичковВ прошлом уроке ты открывал файлы в режиме 'r' и читал содержимое — конструкция with open(...) as f уже знакома. Сейчас меняется только режим: вместо чтения будем писать. И вот здесь сразу возникает выбор, который определяет, что произойдёт с файлом в момент открытия.
Режимы записи 'w' и 'a': перезапись и дозапись
Когда открываешь файл для записи, Python смотрит на второй аргумент функции open() — строку режима. Для записи используются два основных варианта: 'w' и 'a'. Они похожи внешне, но ведут себя принципиально по-разному.
Режим 'w' — перезапись. Как только Python выполняет open('log.txt', 'w'), файл очищается немедленно — ещё до того, как ты вызовешь хоть один метод записи. Если файл существовал и в нём были данные, они безвозвратно удаляются. Если файл не существовал — он создаётся пустым. После этого ты пишешь в чистый файл с нуля.
Режим 'a' — дозапись (append). При открытии файл не трогается: существующее содержимое остаётся нетронутым, а курсор записи встаёт в самый конец. Всё, что ты запишешь, добавится после последней строки. Если файл не существовал — он тоже создаётся, как и в режиме 'w'.
Разница критична на практике. Представь, что log.txt уже содержит записи за прошлый сеанс:
# Режим 'w' — ОСТОРОЖНО: все предыдущие записи будут уничтожены
with open('log.txt', 'w', encoding='utf-8') as f:
f.write('Новый сеанс\n')
# log.txt теперь содержит только одну строку — предыдущие данные стёрты
# Режим 'a' — предыдущие записи сохраняются
with open('log.txt', 'a', encoding='utf-8') as f:
f.write('Новый сеанс\n')
# log.txt содержит всё, что было раньше, плюс эта строка в конце
Главная ловушка режима 'w' в том, что файл стирается в момент открытия, а не в момент записи. Это значит: даже если программа упадёт с ошибкой сразу после open(), не записав ничего, старый файл уже потерян. Поэтому 'w' используют осознанно — когда нужно создать файл заново или перезаписать его целиком. Для накопления данных между запусками правильный выбор — 'a'.
Методы write() и writelines(): запись строк в файл
Когда файл открыт в режиме 'w' или 'a', для записи данных в него используются два метода файлового объекта: write() и writelines().
Метод write() принимает одну строку и записывает её в файл. Ничего лишнего он не делает — в частности, не добавляет перенос строки в конце. Это принципиальное отличие от print(), к которому ты, скорее всего, привык: print('текст') сам ставит \n после вывода, а write('текст') — нет.
Если не добавить \n явно, все вызовы write() запишут данные в одну непрерывную строку:
with open('log.txt', 'w', encoding='utf-8') as f:
f.write('Первое событие')
f.write('Второе событие')
Файл после этого будет содержать:
Первое событиеВторое событие
Чтобы каждая запись оказалась на отдельной строке, \n нужно вставлять самому:
with open('log.txt', 'w', encoding='utf-8') as f:
f.write('Первое событие\n')
f.write('Второе событие\n')
Теперь файл выглядит так, как ожидается:
Первое событие Второе событие
Метод writelines() принимает не одну строку, а итерируемый объект — обычно список строк — и записывает каждый элемент подряд. По поведению это эквивалентно вызову write() для каждого элемента в цикле: никаких разделителей и переносов между элементами не добавляется.
события = [
'Пользователь вошёл\n',
'Открыт файл config.txt\n',
'Пользователь вышел\n',
]
with open('log.txt', 'w', encoding='utf-8') as f:
f.writelines(события)
Это удобно, когда у тебя уже есть готовый список строк и не хочется писать цикл вручную. Но обрати внимание: \n в конце каждой строки списка — снова твоя ответственность. Если написать 'Пользователь вошёл' без \n, строки в файле снова сольются.
Простое правило: и write(), и writelines() пишут ровно то, что ты передаёшь. Хочешь перенос — передай \n. Хочешь, чтобы строки были на отдельных строках — позаботься об этом сам.
Дозапись в действии: режим 'a' и накопление данных
Режим 'a' уже введён, и понятно, что он добавляет данные в конец. Но возникает закономерный вопрос: как Python знает, где именно находится этот конец, если файл закрывался и открывался заново?
Рассмотрим простой случай — два независимых открытия:
# Первый запуск программы
with open('log.txt', 'a', encoding='utf-8') as f:
f.write('10:00 — программа запущена\n')
# ... время прошло, файл закрыт ...
# Второй запуск программы
with open('log.txt', 'a', encoding='utf-8') as f:
f.write('10:15 — пользователь открыл меню\n')
Ответ — на уровне операционной системы. При каждом открытии в режиме 'a' ОС сама находит текущий конец файла и ставит курсор записи туда. Python не читает файл, не считает байты и не запоминает смещение между запусками — это делает ОС при каждом обращении заново.
Из этого следует важное практическое свойство: режим 'a' работает корректно независимо от того, сколько раз файл открывался и закрывался, из одного места кода или из разных. Каждое открытие — это независимый запрос к ОС найти конец файла. Именно поэтому 'a' надёжен для любого сценария накопления данных — от простого цикла до нескольких скриптов, пишущих в один файл по очереди.
Программа сохранения лога действий в файл
Теперь соберём всё изученное в одну рабочую программу. Задача простая: пользователь вводит команды в цикле, а программа записывает каждое действие в файл log.txt.
Вот полный вариант:
print('Программа запущена. Введите действие или "стоп" для завершения.')
while True:
действие = input('> ')
строка = f'Действие: {действие}\n'
with open('log.txt', 'a', encoding='utf-8') as f:
f.write(строка)
if действие.lower() == 'стоп':
break
print('Лог сохранён в log.txt')
Что здесь происходит по шагам:
Программа запрашивает ввод в бесконечном цикле.
Из введённого текста формируется строка лога —
'Действие: открыл меню\n'— с явным\nв конце.Файл открывается в режиме
'a': каждый вызов добавляет строку в конец, не трогая предыдущие записи.Конструкция
withгарантирует, что файл закрывается сразу после записи.Когда пользователь вводит
'стоп', цикл завершается.
После нескольких вводов log.txt будет выглядеть так:
Действие: открыл настройки Действие: изменил имя пользователя Действие: сохранил изменения Действие: стоп
Для учебного логгера файл открывается в режиме 'a' внутри цикла: конструкция with закрывает его после каждой записи, а старые строки сохраняются. Это простой вариант для начинающего; сравнивать стратегии буферизации в этом уроке не требуется.
Если нужно сбросить лог перед новым сеансом, достаточно один раз открыть файл в режиме 'w' в самом начале программы:
# Очищаем лог перед стартом нового сеанса
with open('log.txt', 'w', encoding='utf-8') as f:
f.write('=== Новый сеанс ===\n')
После этого все последующие записи через 'a' будут добавляться к этому чистому началу. Это типичная схема: 'w' один раз при старте для инициализации, 'a' во всём остальном коде для накопления.
Попробуйте решить
Программист открыл существующий файл notes.txt с данными в режиме 'w' и сразу закрыл файл, ничего не записав:
with open('notes.txt', 'w', encoding='utf-8') as f:
pass
Что произойдёт с содержимым файла?
Продолжить с проверкой и прогрессом
Откройте интерактивный раннер с заданиями урока.
