Попытка понять Python с помощью операторов и контекста - PullRequest
15 голосов
/ 12 сентября 2010

Я новичок в этом, и я просто пытаюсь понять утверждение 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"

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

Ответы [ 5 ]

23 голосов
/ 12 сентября 2010

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).

18 голосов
/ 01 августа 2013

Декоратор функций 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

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

14 голосов
/ 12 сентября 2010

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

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

Например, взгляните на классический open() пример:

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

Open возвращает объект File, который реализует __enter__ более или менее как return self и __exit__ как self.close().

6 голосов
/ 06 марта 2017

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

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

пример

Я приведу простой пример, чтобы показать вам, почему нам нужен менеджер контекста. Зимой в Синьцзяне, Китай, вы должны сразу же закрыть дверь, когда откроете дверь. Если вы забудете закрыть ее, выполучите ***. class Door: def __init__(self): self.doorstatus='the door was closed when you are not in 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 in home i have opened the door i have fetched somethings pong!the door has closed

Объяснение

Когда вы инициируете класс Door, он вызовет __ init __ метод, который будет печатать "дверь была закрыта, когдавы не дома "и __ введите метод __ , который напечатает« Я открыл дверь »и вернет экземпляр двери с именем dr.при вызове self.fetchsomethings в блоке метод выведет «Я кое-что получил». Когда блок завершится. Менеджер контекста вызовет метод __ exit __ и выведет «Понг! дверь закрылась ". Когда вы не используете ключевое слово, __ введите __ и __ выход __ не будут вызваны !!!!

5 голосов
/ 12 апреля 2016

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 гарантирует, что, как только вы покинете свой отступ, он закроет дескриптор файла:

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 .Оборачивает генератор как менеджер контекста.

...