Файлы сохраняют данные между запусками программы, а конструкция with гарантирует корректное закрытие файла даже при ошибке.
Зачем нужны файлы?
Данные в переменных живут только пока работает программа. При закрытии — всё теряется.
# Без файла: данные пропадут при закрытии программы
score = 100
player = "Рик"
# С файлом: данные сохраняются между запусками
with open("save.txt", "w") as f:
f.write(f"{player}\n{score}\n")
without vs with: почему важен контекстный менеджер
# Старый способ — легко забыть закрыть файл
f = open("data.txt", "w")
f.write("Данные")
f.close() # Если до этого упала ошибка — файл не закроется!
# Правильный способ — with закрывает файл автоматически
with open("data.txt", "w") as f:
f.write("Данные")
# Файл закрыт здесь, даже если внутри была ошибка
Режим “w” — запись
with open("battle_log.txt", "w") as f:
f.write("=== ЛОГ БИТВЫ ===\n")
f.write("Рик атакует Ходока\n")
f.write("Урон: 20\n")
Внимание: режим "w" перезаписывает файл полностью при каждом открытии.
class Player:
def __init__(self, name):
self.name = name
self.kills = 0
self.health = 100
def save(self):
with open(f"saves/{self.name}.txt", "w") as f:
f.write(f"{self.name}\n")
f.write(f"{self.kills}\n")
f.write(f"{self.health}\n")
print(f"Сохранено: {self.name}")
player = Player("Рик")
player.kills = 5
player.save()
Режим “r” — чтение
with open("saves/Рик.txt", "r") as f:
content = f.read() # Весь файл строкой
print(content)
Способы чтения
with open("saves/Рик.txt", "r") as f:
name = f.readline().strip() # Первая строка
kills = f.readline().strip() # Вторая строка
health = f.readline().strip() # Третья строка
print(f"{name}: {kills} убийств, {health} HP")
with open("battle_log.txt", "r") as f:
lines = f.readlines() # Список строк
for line in lines:
print(line.strip())
strip() убирает символ \n в конце строки.
class Player:
@staticmethod
def load(name):
with open(f"saves/{name}.txt", "r") as f:
loaded_name = f.readline().strip()
kills = int(f.readline().strip())
health = int(f.readline().strip())
p = Player(loaded_name)
p.kills = kills
p.health = health
return p
rick = Player.load("Рик")
print(f"{rick.name}: {rick.kills} убийств, {rick.health} HP")
Режим “a” — дозапись
Режим "a" добавляет в конец файла, не удаляя предыдущее содержимое:
with open("log.txt", "w") as f:
f.write("Лог запущен\n")
# Позже добавляем события
with open("log.txt", "a") as f:
f.write("Рик убил Ходока\n")
with open("log.txt", "a") as f:
f.write("Дэрил убил Бегуна\n")
# Файл:
# Лог запущен
# Рик убил Ходока
# Дэрил убил Бегуна
Таблица режимов
| Режим | Что делает | Если файла нет |
|---|---|---|
"r" |
Читает | Ошибка |
"w" |
Записывает (перезаписывает) | Создаёт |
"a" |
Добавляет в конец | Создаёт |
Частые ошибки
Ошибка 1: Забыли режим
# ❌ По умолчанию "r" — нельзя писать
with open("data.txt") as f:
f.write("Данные") # UnsupportedOperation: not writable
# ✅ Указывай режим явно
with open("data.txt", "w") as f:
f.write("Данные")
Ошибка 2: Файл не найден
# ❌ Файл отсутствует
with open("saves/данные.txt", "r") as f:
content = f.read() # FileNotFoundError
# ✅ Обработка ошибки
try:
with open("saves/данные.txt", "r") as f:
content = f.read()
except FileNotFoundError:
print("Файл не найден — начинаем заново")
content = ""
Пользовательский контекстный менеджер
with работает с любым объектом, реализующим __enter__ и __exit__:
class Timer:
import time
def __enter__(self):
import time
self.start = time.time()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
import time
elapsed = time.time() - self.start
print(f"Время выполнения: {elapsed:.3f}s")
return False # False — не подавлять исключения
with Timer():
total = sum(range(1_000_000))
# Время выполнения: 0.031s
__enter__ выполняется при входе в блок with, __exit__ — при выходе (в том числе при ошибке).
💬 Комментарии (0)
Комментариев пока нет
Станьте первым, кто поделится мнением об этой статье!