Skip to content

Latest commit

 

History

History
103 lines (84 loc) · 4.71 KB

With.md

File metadata and controls

103 lines (84 loc) · 4.71 KB

Менеджеры контекста with


При работе с некоторым ресурсом, в конце этот ресурс должен быть освобожден, при работе с исключениями мы делаем это в блоке finally этот блок выполнятся в любом случае, так открыв дескриптор файла его можно закрыть в финальном блоке.

Это освобождение ресурса является настолько необходимым, что для него существует специальный отдельный синтаксис, так называемый менеджер контекста.

with - получает ресурс и работает с ним под неким псевдонимом, и по завершению работы ресурс сам себя завершит.

Пример работы исключения против менеджера контекста with :

  1. Первый пример
    # Пример открытия фалйа и его закрытие при помощи исключений
    try:
        file = open('file.txt', 'r')
        print("Пример с исключениями")
        for line in file:
            print(line)
    except Exception:
        raise
    finally:
        file.close()
  1. Второй пример
    # Тот же пример но с менеджером контекста
    try:
        with open('file.txt', 'r') as file:
            print("Пример с менеджером контекста")
            for line in file:
                print(line)
    except Exception:
        raise

Создадим свой собственный менеджер контекста

По сути менеджер контекста это класс который реализует 2 магических метода, __enter__() и __exit__().

__enter__() - метод что принимает входящее значение, в данном случае это open('file.txt', 'r') открытый на запись дескриптор файла, а возвращает этот метод то что попадет в псевдоним as file

__exit__() - по завершению работы блока with вызывается метод __exit__() в котором можно закрыть дескриптор класса, и происходит это даже в том случае если в процессе работы возникло исключение.

Функция выхода имеет свои аргументы def __exit__(self, exc_type, exc_val, exc_tb): где аргумент exc_type держит в себе все исключения которые могли возникнуть, или содержит None тут мы можем перехватить это исключение, если все шло по плану то исключений не будет, если ошибка возникла то тут мы его и увидим.

В след примере мы создаем 2 вектора и с помощью оператора менеджер контекста складываем эти вектора вместе, случае если произошла ошибка мы отловим ее в __exit__ и не будет сохранять новый высчитанный вектор, а если ошибки не было то мы сохраним вычисления.

    class VectorTesting:

        def __init__(self, vector):
            self.__vector = vector

        def __enter__(self):
            self.temp = self.__vector[:]
            return self.temp

        # return False - обработка исключений передается на более
        # верхний уровень. True -  будет уходить на ур выше.
        def __exit__(self, exc_type, exc_val, exc_tb):
            if exc_type is None:
                self.__vector[:] = self.temp
            return False

    # Пример работы с вектором
    vector_1 = [1, 2, 3]
    vector_2 = [5, 5, 5]
    print('vector_1 = ', vector_1)
    print('vector_2 = ', vector_2)

    # Складываем 2 вектора одинаковой длинны
    try:
        with VectorTesting(vector_1) as vector_temp:
            for i in range(len(vector_temp)):
                vector_temp[i] += vector_2[i]
    except Exception as e:
        print('Произошло исключение = ', e)

    print('Новый vector_1 = ', vector_1)