В этом руководстве я покажу вам, как использовать оператор with
для упрощения открытия и обработки файлов в ваших программах Python.
Оператор with создает менеджер контекста, который упрощает способ открытия и закрытия файлов в программах Python. Без использования оператора with разработчик должен помнить о необходимости закрыть обработчики файлов. Это автоматически делается Python при использовании шаблона with open … as
.
Начнем с открытия файла без оператора with
, а затем увидим преимущества использования оператора with
.
Давайте начнем!
Синтаксис открытия файла в Python без использования оператора With
Я создал файл output.txt со следующим содержимым:
$ cat output.txt
Line1
Line2
Line3
Line4
Line5
Давайте посмотрим на определение функции open из документации Python:
В этом руководстве мы сосредоточимся на первых двух аргументах функции open: file и mode.
Вот как мы можем открыть наш файл в режиме чтения, используя функцию open
.
Режим чтения установлен по умолчанию.
>>> f = open('output.txt')
>>> f.read()
'Line1\nLine2\nLine3\nLine4\nLine5\n'
>>> f.close()
>>> f.closed
True
Мы используем функцию open для создания обработчика файла (f), а затем используем обработчик файла для чтения содержимого файла с помощью функции read()
.
После прочтения содержимого файла мы используем функцию close()
для закрытия обработчика.
Запустив f.closed
, мы получим True
как подтверждение того, что обработчик файлов закрыт.
Давайте посмотрим, как выглядит объект файла в предыдущем примере:
>>> f = open('output.txt')
>>> print(f)
<_io.TextIOWrapper name='output.txt' mode='r' encoding='UTF-8'>
>>> print(f.__dict__)
{'mode': 'r'}
Он имеет тип TextIOWrapper, его кодировка по умолчанию — UTF-8, и у него есть атрибут mode.
Чтобы узнать, какие методы можно использовать для этого файлового объекта, выполните следующую команду в оболочке Python:
>>> help(f)
Примечание: Режим чтения — это режим по умолчанию, используемый Python для открытия файлов, если только вы не передадите второй параметр в функцию открытия (см. несколько примеров ниже):
Режим | Пример |
---|---|
r (чтение – текстовый формат) | f = open(filename, 'r') |
rb (чтение – двоичный формат) | f = open(filename, 'rb') |
w (запись – текстовый формат, обрезает файл) | f = open(filename, 'w') |
wb (запись – двоичный формат, обрезает файл) | f = open(filename, 'wb') |
r+ (чтение и запись – текстовый формат) | f = open(filename, 'r+') |
a (append – текстовый формат, добавляет в конец файла) | f = open(filename, 'a') |
Как прочитать файл с помощью with open … as в Python
Давайте посмотрим, что произойдет, если мы используем оператор with
при открытии файлов в Python.
Синтаксис, который мы будем использовать, следующий:
with open(file, mode) as file_object
При использовании оператора with
файл автоматически закрывается, когда он больше не нужен. Это подтверждается тем фактом, что в следующем коде f.closed
возвращает True
.
>>> with open('output.txt') as f:
... data = f.read()
...
>>> f.closed
True
Очистка ресурсов в вашей системе крайне важна. Представьте, что вы создаете программу, которая открывает сотни файлов и не закрывает их. Как долго она может работать, прежде чем израсходует все системные ресурсы?
Итак, подведем итоги…
Если вы не используете ключевое слово with
, вам нужно помнить о вызове f.close()
для освобождения ресурсов, когда файл вам больше не нужен. Запуск f.close()
не требуется при использовании оператора with
.
Что произойдет, если мы попытаемся прочитать файл, который уже закрыт?
>>> f.closed
True
>>> f.read()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: I/O operation on closed file.
Python вызывает исключение ValueError.
Распечатать все строки в файле с помощью with open … as
Давайте выясним, как распечатать все строки файла после открытия файла с помощью оператора with
.
Мы будем использовать файл output.txt, использованный в предыдущем примере, и перебирать строки в файле по одной:
with open('output.txt', 'r+') as f:
for line in f:
print(line)
Мы передали r+
в качестве второго параметра, чтобы открыть файл для чтения и записи.
Как вы можете видеть, я использую цикл for для прохода по строкам файла, используя файловый объект.
$ python with_open_example.py
Line1
Line2
Line3
Line4
Line5
По какой-то причине оператор печати добавляет новые символы строки, которых нет в исходном файле.
Чтобы избавиться от них, можно использовать следующий синтаксис:
print(line, end='')
Наш код становится следующим:
with open('output.txt', 'r+') as f:
for line in f:
print(line, end='')
[output]
$ python with_open_example.py
Line1
Line2
Line3
Line4
Line5
Теперь выглядит хорошо 🙂
Открытие нескольких файлов в одном операторе with
Представьте, что вам нужно написать программу, которая берет один список строк и записывает каждую строку в один из двух файлов.
Например, предположим, что у нас есть следующий список:
items = ['dog', 'cat', 'apple', 'pear', 'lion', 'banana']
И наша программа должна записывать животных в файл с именем animals.out, а фрукты — в другой файл с именем fruits.out.
Вот как это можно сделать, используя два оператора open в одном выражении with:
items = ['dog', 'cat', 'apple', 'pear', 'lion', 'banana']
with open('animals.out', 'w') as animals_f, open('fruits.out', 'w') as fruits_f:
for item in items:
if item in ['dog', 'cat', 'lion']:
animals_f.write(item+'\n')
if item in ['apple', 'pear', 'banana']:
fruits_f.write(item+'\n')
Давайте запустим программу и убедимся, что два файла созданы, как мы и ожидали:
$ python with_open_example.py
$ cat fruits.out
apple
pear
banana
$ cat animals.out
dog
cat
lion
Для использования двух открытых операторов в одном выражении требуется Python 2.7, Python 3.1 или более новая версия.
Использование вложенных операторов with open в Python
Также можно вкладывать открытые операторы друг в друга вместо использования двух открытых операторов в одной строке.
Вот как мы можем обновить нашу предыдущую программу, используя два вложенных оператора:
items = ['dog', 'cat', 'apple', 'pear', 'lion', 'banana']
with open('animals.out', 'w') as animals_f:
with open('fruits.out', 'w') as fruits_f:
for item in items:
if item in ['dog', 'cat', 'lion']:
animals_f.write(item+'\n')
if item in ['apple', 'pear', 'banana']:
fruits_f.write(item+'\n')
Ниже вы можете видеть, что программа по-прежнему делает то, что должна делать 🙂
$ python with_open_example.py
$ cat fruits.out
apple
pear
banana
$ cat animals.out
dog
cat
lion
Использование Python с open для работы с бинарными файлами
Мы часто работаем с текстовыми файлами, но как насчет двоичных файлов?
Например, как бы вы открыли файл PNG, используя то, что мы узнали об операторе with
?
В текущем каталоге я загрузил картинку под названием python.png:
$ ls -ltr
total 208
-rw-r--r--@ 1 myuser mygroup 102916 22 Feb 20:13 python.png
Из вывода команды ls
выше мы уже знаем, что его размер составляет 102916 байт.
Давайте откроем его и проверим его размер в Python.
Как получить количество байтов в файле с помощью Python?
with open('python.png', 'rb') as png_file:
bytes_count = 0
while png_file.read(1):
bytes_count += 1
print("The size of the file is: {}".format(bytes_count))
Вот что мы сделали в нашем коде:
- Используем
with open … as
для открытия файла PNG в двоичном режиме. - Считываем по одному байту, используя цикл while, пока не достигнем конца файла.
- Увеличиваем значение целого числа bytes_count каждый раз, когда мы считываем байт.
Результат работы программы:
$ python read_binary_file.py
The size of the file is: 102916
Размер файла, рассчитанный нашей программой, совпадает с размером, показанным командой ls
. Отлично!
Использование Try Finally как эквивалента with open … as
Чтобы дать вам полное представление об операторе with, я также хочу показать вам альтернативный способ написания логики, которая ведет себя как with open … as
.
Мы будем использовать оператор try … finally
, чтобы убедиться, что объект файла всегда закрыт после выполнения блока кода try
. Я хочу написать что-то похожее на следующее:
>>> with open('output.txt') as f:
... data = f.read()
Вот код:
>>> f = open('output.txt')
>>> try:
... data = f.read()
... finally:
... f.close()
...
>>> f.closed
True
Видите ли вы преимущество использования with open
вместо этого?
Это определенно делает наш код более лаконичным. Представьте, если бы нам пришлось использовать операторы try … finally
для каждого открываемого файла!
Заключение
В этом простом руководстве мы увидели, как использовать команду open
в Python для упрощения работы с файлами.
Попрактикуйтесь в его синтаксисе несколько раз, и вы без проблем его запомните, когда бы он вам ни понадобился в будущем.