Пытаясь понять Python с оператором и менеджерами контекста

StackOverflow https://stackoverflow.com/questions/3693771

  •  02-10-2019
  •  | 
  •  

Вопрос

Я новичок в этом, и просто пытаюсь понять with утверждение. Я понимаю, что предполагается заменить try/except блокировать.

Теперь предположим, что я делаю что-то вроде этого:

try:
   name='rubicon'/2 # to raise an exception
except Exception as e:
   print "no not possible"
finally:
   print "Ok I caught you"

Как мне заменить это менеджером контекста?

Это было полезно?

Решение

with на самом деле не заменяет try/except, скорее, try/finally. Отказ До сих пор вы могу Сделать менеджер контекста сделать что-то другое в исключительных случаях от не исключения:

class Mgr(object):
    def __enter__(self): pass
    def __exit__(self, ext, exv, trb):
        if ext is not None: print "no not possible"
        print "OK I caught you"
        return True

with Mgr():
    name='rubicon'/2 #to raise an exception

То return True часть там, где менеджер контекста решает подавить исключение (как вы делаете, не повторно поднимая его в своем except пункт).

Другие советы

То contextlib.contextmanager. Функциональный декоратор обеспечивает удобный способ предоставления контекстно-менеджера без необходимости написать полноценный ContextManager класс самостоятельно (с __enter__ и __exit__ методы, так что вам не нужно помнить аргументы __exit__ метод или что __exit__ Метод должен return True Для того, чтобы подавить исключение). Вместо этого вы пишете функцию с одним yield в точке, который вы хотите with блок для запуска, и вы ловушаете любые исключения (которые эффективно приходят из yield) Как вы обычно бы.

from contextlib import contextmanager
@contextmanager
def handler():
    # Put here what would ordinarily go in the `__enter__` method
    # In this case, there's nothing to do
    try:
        yield # You can return something if you want, that gets picked up in the 'as'
    except Exception as e:
        print "no not possible"
    finally:
        print "Ok I caught you"

with handler():
    name='rubicon'/2 #to raise an exception

Зачем идти к дополнительной неприятности написания контекста менеджера? Повторно использовать код. Вы можете использовать тот же менеджер контекста в нескольких местах, без необходимости дублирования обработки исключений. Если обработка исключений уникальна для этой ситуации, то не беспокойтесь о контексте менеджера. Но если один и тот же шаблон порекомендуется снова и снова (или, или если это может для ваших пользователей, например, закрывая файл, разблокируя Mutex), это стоит дополнительных проблем. Это также аккуратный узор для использования, если обработка исключений немного сложна, поскольку он отделяет обращение с исключением от основной линии потока кода.

То with В Python предназначен для обертывания набора утверждений, в которых вы должны устанавливать и уничтожать или закрывать ресурсы. Это похоже на try...finally В этой связи как о последнее предложение будет выполнено даже после исключения.

Контекстный менеджер - это объект, который реализует два метода: __enter__ и __exit__. Отказ Те, которые называются непосредственно до и после (соответственно) with блокировать.

Например, посмотрите на классику open() пример:

with open('temp.txt', 'w') as f:
    f.write("Hi!")

Открытые возвраты A. File объект, который реализует __enter__ более или меньше, как return self и __exit__ нравится self.close().

Компоненты контекста менеджера

  1. Вы должны реализовать __войти__ метод, который возвращает объект
  2. Реализовать А. __выход__ метод.

Пример

Я дам простой пример, чтобы показать вам, почему нам нужен менеджер контекста. Во время зимы Синьцзяна, Китай, вы должны немедленно закрыть дверь, когда вы открываете дверь. Если вы забудете закрыть его, вы будете простужаться.

 class Door:
     def __init__(self):
         self.doorstatus='the door was closed when you are not at home'
         print(self.doorstatus)
     def __enter__(self):
         print('I have opened the door')
         return self
     def __exit__(self,*args):
         print('pong!the door has closed')
     def fetchsomethings(self):
         print('I have fetched somethings')

При извлечении вещей дома, вы должны открыть дверь, извлечь что-нибудь и закройте дверь.

 with Door() as dr:
     dr.fetchsomethings()

Выход:

the door was closed when you are not at home
I have opened the door
I have fetched somethings
pong!the door has closed

Объяснение

Когда вы инициируете дверной класс, он позвонит __в этом__ Метод, который напечатает «дверь была закрыта, когда вы не дома» и __войти__ Метод, который будет печать «Я открыл дверь» и вернул экземпляр двери под названием DR. при вызове self.fetchsometings. В с блоком метод будет печать «я привлек что-нибудь». Когда блок закончен. __выход__Метод и он будет печатать "понг! дверь закрылась". Когда вы не используете с ключевым словом,__войти__и __выход__ не будет вызван !!!!

with Заявления или контекстные менеджеры должны помочь с ресурсами (хотя могут быть использованы для гораздо больше).

Допустим, вы открыли файл для написания:

f = open(path, "w")

Теперь у вас есть дескриптор открытых файлов. Во время обработки вашего файла ни одна другая программа не может написать ему. Чтобы позволить другим программам писать ему, вы должны закрыть дескриптор файла:

f.close()

Но, прежде чем закрывать свой файл, произошла ошибка:

f = open(path, "w")
data = 3/0  # Tried dividing by zero. Raised ZeroDivisionError
f.write(data)
f.close()

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

А с оператором гарантирует, что как только вы оставляете его отступ, он закроет дескриптор файла:

with open(path, "w") as f:
    data = 3/0  # Tried dividing by zero. Raised ZeroDivisionError
    f.write(data)
# In here the file is already closed automatically, no matter what happened.

with Отчеты могут быть использованы для многих вещей. Например: threading.Lock()

lock = threading.Lock()
with lock:  # Lock is acquired
   do stuff...
# Lock is automatically released.

Почти все сделано с менеджером контекста, может быть сделано с try: ... finally: ... Но контекстные менеджеры приятнее использовать, более удобные, более читаемые и реализующимися __enter__ и __exit__ Предоставьте простой в использовании интерфейс.


Создание контекстных менеджеров выполняется путем реализации __enter__() и __exit__() в нормальном классе.

__enter__() говорит, что делать, когда менеджер контекста начинается и __exit__() Когда контекстный менеджер существует (давая исключение к __exit__() Метод, если произошло исключение)

Ярлык для создания контекстных менеджеров можно найти в Contextlib. Отказ Он обертывает генератор как менеджер контекста.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top