Ввод-вывод
Файлы, потоки, буферизация и работа с кодировками.
9 вопросов
JuniorТеорияОчень частоЧто означают режимы open(): r, w, x, a, t, b, +?
Что означают режимы open(): r, w, x, a, t, b, +?
r читает; w пишет и обрезает файл; x создаёт эксклюзивно и падает, если файл есть; a дописывает. Вторая буква задаёт тип: t текст (по умолчанию) или b бинарный. + открывает и на чтение, и на запись.
Типичные ошибки
- ✗Использовать
wи терять содержимое файла, потому что он обрезается при открытии - ✗Ожидать, что
xоткроет существующий файл, а не упадёт, если он есть - ✗Думать, что
aпишет с начала, а не дописывает в конец
Уточняющие вопросы
- →Что меняет сочетание
w+противr+в начальном состоянии файла? - →Почему режим
xпомогает избежать гонок при создании lock-файла?
JuniorТеорияЧастоЧто такое файловый объект в Python?
Что такое файловый объект в Python?
Объект, дающий файловый API (read(), write(), close(), итерацию) поверх ресурса: файла на диске, буфера в памяти, канала или сокета. Его зовут потоком; это контекстный менеджер, пригодный для with.
Типичные ошибки
- ✗Считать, что файловый объект всегда оборачивает физический файл на диске, а не любой поток
- ✗Забывать, что файловые объекты — контекстные менеджеры, пригодные для
with - ✗Путать файловый объект со строкой пути, переданной в
open()
Уточняющие вопросы
- →Что возвращает итерация по текстовому файловому объекту на каждом шаге?
- →Как
with open(...)гарантирует закрытие файла при исключении?
JuniorТеорияЧастоЧем текстовый и бинарный режимы файла различаются?
Чем текстовый и бинарный режимы файла различаются?
Текстовый режим читает и пишет str, применяя кодировку и преобразование переводов строк. Бинарный режим ('b') читает и пишет сырые bytes/bytearray без кодировки и преобразования — ровно байты на диске.
Типичные ошибки
- ✗Открывать бинарные данные вроде изображений в текстовом режиме, портя их декодированием
- ✗Ожидать, что
read()в бинарном режиме вернётstr, а неbytes - ✗Забывать, что текстовый режим преобразует переводы строк и применяет кодировку
Уточняющие вопросы
- →Какой параметр
open()задаёт кодировку, используемую в текстовом режиме? - →Почему сетевые протоколы и изображения нужно читать в бинарном режиме?
MiddleТеорияЧастоЧем сериализация через json и pickle различается?
Чем сериализация через json и pickle различается?
json создаёт человекочитаемый текст, кросс-языковой, но поддерживает только базовые типы (dict, list, str, число, bool, None). pickle создаёт специфичный для Python бинарный формат и сериализует почти любой объект, но не переносим между языками.
Типичные ошибки
- ✗Пытаться
json.dumpsпользовательский объект или set без своего энкодера - ✗Ожидать, что вывод
pickleчитаем или разбираем другими языками - ✗Использовать
pickleдля данных, пересекающих границу доверия или языка
Уточняющие вопросы
- →В какие типы Python
jsonотображает данные и обратно из коробки? - →Почему
pickleбыстрееjsonдля больших вложенных объектов Python?
MiddleТеорияИногдаЗачем закрывать файлы, и как с этим связана буферизация?
Зачем закрывать файлы, и как с этим связана буферизация?
Буферизованные записи лежат в памяти и попадают на диск только при заполнении буфера или вызове flush()/close(), так что незакрытие теряет данные и держит блокировку. close() сбрасывает буфер и освобождает дескриптор; with это гарантирует.
Типичные ошибки
- ✗Считать, что записи сохраняются сразу, и пропускать
close()илиwith - ✗Думать, что
close()освобождает дескриптор, не сбрасывая буфер - ✗Полагаться на сборку мусора для предсказуемого закрытия файлов
Уточняющие вопросы
- →Когда стоит вызвать
flush()явно, а не ждатьclose()? - →Что контролирует аргумент
bufferingуopen()?
MiddleТеорияИногдаДля чего нужны io.StringIO и io.BytesIO?
Для чего нужны io.StringIO и io.BytesIO?
Потоковые объекты в памяти с тем же файловым API: io.StringIO хранит текст (str), io.BytesIO хранит bytes. Они дают коду, ждущему файл, работать с памятью — удобно для тестов или захвата вывода.
Типичные ошибки
- ✗Писать
bytesвio.StringIOилиstrвio.BytesIOи получать ошибку типа - ✗Думать, что они опираются на диск, а не живут целиком в памяти
- ✗Забывать
seek(0)перед чтением только что записанного содержимого
Уточняющие вопросы
- →Как получить всё накопленное содержимое через
getvalue()? - →Почему
io.StringIOудобен для перенаправления и захвата выводаprint?
MiddleТеорияИногдаЧто делают методы файлового объекта tell() и seek()?
Что делают методы файлового объекта tell() и seek()?
tell() возвращает текущую позицию в потоке; seek(offset, whence) перемещает её, где whence — 0 (начало), 1 (текущая) или 2 (конец). В бинарном режиме позиционируешься свободно по байтам; в текстовом offset должен быть значением из tell(), ведь кодировки делают сырую арифметику небезопасной.
Типичные ошибки
- ✗Считать, что
tell()/seek()считают в строках, а не в байтах - ✗Делать арифметику над позициями текстового режима вместо повторного использования значения
tell() - ✗Забывать, что
seek(0)отматывает поток, чтобы файл можно было перечитать
Уточняющие вопросы
- →Почему арифметика байтовых смещений небезопасна в текстовом режиме, но допустима в бинарном?
- →Что говорит о файле
seek(0, 2)с последующимtell()?
SeniorТеорияРедкоКак сериализовать в JSON объект, который json не поддерживает из коробки?
Как сериализовать в JSON объект, который json не поддерживает из коробки?
json понимает только dict, list, str, числа, bool и None. Для всего прочего — set, Decimal или своего класса — передай default=func в dumps; он зовётся на каждый объект и должен вернуть сериализуемое значение. Либо унаследуй JSONEncoder и переопредели default. При загрузке типы восстановит object_hook.
Типичные ошибки
- ✗Ждать, что
jsonсериализуетdatetime,setили свои классы без помощи - ✗Возвращать из
defaultнесериализуемое значение вместо встроенного типа - ✗Забывать, что при декодировании нужен
object_hook, чтобы восстановить исходный тип
Уточняющие вопросы
- →Когда стоит взять
pickleвместо своего энкодераjson? - →Как
defaultрешает, для каких объектов его вызывают?
SeniorТеорияРедкоПочему распаковка недоверенных данных через pickle опасна?
Почему распаковка недоверенных данных через pickle опасна?
pickle небезопасен: загрузка pickle может выполнить произвольный код через __reduce__ объекта, так что распаковка недоверенных данных запускает код атакующего. Никогда не распаковывайте недоверенный ввод; берите json или подписанный формат.
Типичные ошибки
- ✗Распаковывать сетевые или пользовательские данные без подписи и проверки
- ✗Считать, что один лишь бинарный формат мешает выполнению кода при загрузке
- ✗Думать, что
jsonтак же опасен, и потому не видеть смысла переходить
Уточняющие вопросы
- →Как
__reduce__объекта позволяет выполнить код при распаковке pickle? - →Какая схема подписи или HMAC сделает загрузку pickle-нагрузки безопаснее?