с заявлением в Python

| | | | | | | | | | | | | | | | | | | | | | | | | |

# обработка файлов


# 1) не используется с оператором

файл = open ( `file_path` , `w` )

файл . write ( `hello world!` )

файл . закрыть ()


# 2) не использовать с оператором

файл = open ( `file_path` , `w` )

try :

файл . write ( `hello world` )

наконец :

file .close ()


# использовать с оператором

with open ( ` file_path` , `w` ) as файл :

файл . write ( `hello world!` )

Обратите внимание, что в отличие от первых двух реализаций нет необходимости вызывать file.close() при использовании инструкции with . Сам оператор with обеспечивает правильное получение и освобождение ресурсов. Исключение при file.write() в первой реализации может помешать правильному закрытию файла, что может привести к нескольким ошибкам в коде, т.е. многие изменения в файлах не вступят в силу, пока файл не будет должным образом закрыты.

Второй подход в приведенном выше примере позаботится обо всех исключениях, но использование инструкции with делает код компактным и более читабельным. Таким образом, оператор with помогает избежать ошибок и утечек, гарантируя, что ресурс освобождается должным образом, когда код, использующий ресурс, полностью выполнен. Оператор with обычно используется с файловыми потоками, как показано выше, а также с блокировками, сокетами, подпроцессами, telnet и т. д.

Поддержка оператора with в пользовательских объектах

В open() нет ничего особенного, что делает его пригодным для использования с оператором with with , и та же функциональность может предоставляться в пользовательских объектах. Поддержка утверждений с в ваших объектах гарантирует, что вы никогда не оставите открытыми ресурсы.
Чтобы использовать оператор с в пользовательских объектах, вам нужно всего лишь добавить __enter __() и __exit __() к методам объекта. Для дальнейшего пояснения рассмотрим следующий пример.


# простой модуль записи файлов


class MessageWriter ( object ):

def __ init __ ( self , file_name):

self . имя_файла = имя_файла


def __ введите __ ( self ):

self . файл = открыть ( self . имя_файла, ` w` )

return self . файл

def __ exit __ ( self ):

self . файл . close ()


# использовать с оператором с MessageWriter


с MessageWriter ( `my_file.txt` ) как xfile:

xfile.write ( `hello world` )

Давайте посмотрим на приведенный выше код. Если вы заметили, что ключевое слово with следует за конструктором MessageWriter . Как только выполнение входит в контекст with путем утверждения объекта MessageWriter , создается объект, а затем python вызывает метод __enter __() . В этом __enter __() инициализируйте ресурс, который вы хотите использовать в объекте. Этот __enter __ () всегда должен возвращать дескриптор полученного ресурса.

Что такое дескрипторы ресурсов?
Это дескрипторы, предоставляемые операционной системой для доступа к запрошенным ресурсам. В следующем блоке кода file является дескриптором ресурса файлового потока.


file = open ( `hello.txt ` )

В предоставленном примере MessageWriter __enter __() метод __enter __() создает дескриптор файла и возвращает его. Имя xfile используется здесь для обозначения файлового дескриптора, возвращаемого методом __enter __() . Блок кода, использующий полученный ресурс, помещается внутрь блока операторов with . После выполнения кода внутри блока with метод __exit __() становится __exit __() . Все полученные ресурсы освобождаются в __exit__(). Вот как мы используем утверждение with с определяемыми пользователем объектами.

Этот интерфейс метода — __enter __ () и __exit __ () , обеспечивающий поддержку оператора with в пользовательских объектах, называется Context Manager .

Модуль contextlib

Контекстный менеджер на основе классов, как показано выше, — не единственный способ поддержки оператора with в пользовательских объектах. Модуль contextlib предоставляет дополнительные абстракции, построенные на базовом интерфейсе. менеджер контекста. Вот как мы можем переписать менеджер контекста для объекта MessageWriter , используя модуль contextlib .


< / p>

from contextlib import менеджер контекста


класс MessageWriter ( object ):

def __ init __ ( self , имя файла):

self . имя_файла = имя файла

@ contextmanager

def open_file ( self ):

попробовать :

файл = open ( self .file_name, `w` )

yield file

наконец :

файл . close ()


# use

message_writer = MessageWriter ( `hello.txt` )

с message_writer.open_file() as my_file:

my_file.write ( `hello world` )

< / p>

В этом примере кода из-за оператора генератором функций .
Когда open_file() этот open_file() , он создает дескриптор ресурса с именем file . Затем этот дескриптор ресурса передается вызывающему объекту и представляется здесь переменной my_file . После выполнения кода внутри блока with управление программой возвращается обратно к функции open_file() . Функция open_file() возобновляет свое выполнение и выполняет код, следующий за оператором yield . Эта часть кода, которая появляется после оператора yield , освобождает результирующие ресурсы. @contextmanager здесь находится