Попытка понять python с помощью операторов и контекстных менеджеров
Я новичок в этом, и я просто пытаюсь понять 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"
как заменить это на context manager?
5 ответов
with
на самом деле не заменяет try
/except
, а try
/finally
. И все же ты!--9-->can заставьте контекстный менеджер делать что-то другое в исключительных случаях от неисключительных:
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
The 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
зачем тратить время на написание контекстного менеджера? Повторное использование кода. Можно использовать один и тот же менеджер контекста в нескольких местах без необходимости дублировать обработку исключений. Если обработка исключений уникальна для этой ситуации, не беспокойтесь о менеджере контекста. Но если один и тот же шаблон появляется снова и снова (или если это может быть для ваших пользователей, например, закрытие файла, разблокировка мьютекса), это стоит дополнительных хлопот. Это также аккуратный шаблон для использования, если обработка исключений немного сложна, поскольку она отделяет обработку исключений от основной строки потока кода.
на with
в Python предназначен для упаковки набора операторов, где вы должны настроить и уничтожить или закрыть ресурсы. Это похоже на try...finally
в этом отношении предложение finally будет выполнено даже после исключения.
менеджер контекста-это объект, реализующий два метода:__enter__
и __exit__
. Они называются непосредственно перед и ПОСЛЕ (соответственно)with
блок.
например, взгляните на классический open()
пример:
with open('temp.txt', 'w') as f:
f.write("Hi!")
"открыть" возвращает File
объект, который реализует __enter__
более-менее return self
и __exit__
как self.close()
.
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. Он обертывает генератор как менеджер контекста.
компоненты context manager
1.вы должны реализовать __enter__ метод, возвращающий объект 2.реализовать__выход__ метод
пример
я приведу простой пример, чтобы показать вам, почему нам нужен context manager.Во время зимы Синьцзяна, Китай, вы должны закрыть дверь немедленно когда вы раскрываете дверь.если вы забыли
чтобы закрыть его ,вы получите ***.
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
Explation
когда вы инициируете класс двери, он будет вызывать _ _ init__ метод, который будет печатать "дверь была закрыта, когда вас не было дома" и __enter__ метод, который напечатает "я открыл дверь" и вернет экземпляр двери под названием dr. когда звонят self.fetchsomethings в с блоком, метод напечатает "я получил что-то".Когда блок закончен.менеджер контекста вызовет __выход__ метод и он напечатает " понг!дверь закрылась" .когда вы не используйте с ключевое слово ,__enter__и __выход__ не будет вызываться!!!!