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

python contextmanager

9302 просмотра

5 ответа

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

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

Автор: user444997 Источник Размещён: 12.11.2019 09:10

Ответы (5)


24 плюса

Решение

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статье).

Автор: Alex Martelli Размещён: 12.09.2010 04:46

18 плюса

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

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

Автор: Paul Price Размещён: 01.08.2013 07:48

14 плюса

В withPython предназначен для упаковки набора операторов, где вы должны установить и уничтожить или закрыть ресурсы. Это похоже на 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().

Автор: Pablo Alejandro Costesich Размещён: 12.09.2010 04:47

7 плюса

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

  1. Вы должны реализовать метод __enter__, который возвращает объект
  2. Реализация __exit__ метода.

пример

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

 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

объяснение

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

Автор: 未来陆家嘴顶尖的投资人 Размещён: 06.03.2017 10:42

5 плюса

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

Автор: Bharel Размещён: 12.04.2016 06:42
Вопросы из категории :
32x32