Как не думать о последствиях при приобретении ресурсов
Представьте себе: вы автоматизировали какие-то действия на веб-странице через Selenium, и все отлично работает. Но бывают случаи, когда он может дать сбой. Вы не хотите if
каждый шаг, который может пойти не так.
Очень изящным решением будет контекстный менеджер. Вы уже использовали его при открытии файлов. Этот with open
является диспетчером контекста. Он пытается получить ресурс и закрывает его, если что-то пойдет не так, освобождая данный ресурс.
Вернемся к нашему примеру с Selenium. Когда происходит сбой, окно браузера не закрывается, оставляя его висеть до тех пор, пока вы его не закроете. Было бы здорово, если бы это окно закрывалось в случае сбоя программы?
Есть несколько способов реализовать Context Manager в Python. Во-первых, это определение класса:
from settings import web_driver class ContextDriver: def __init__(self): self.driver = web_driver def __enter__(self): return self.driver def __exit__(self): self.driver.close()
Драйвер в настройках представляет собой простой веб-драйвер Firefox selenium:
from selenium import webdriver web_driver = webdriver.Firefox()
И это все! Теперь вы можете написать with ContextDriver() as driver
и использовать это driver
для выполнения автоматизации. Поэтому, если что-то пойдет не так, окно браузера закроется.
На мой взгляд, писать класс для такой простой задачи избыточно. К счастью, в Python у нас есть полезный декоратор:
from contextlib import contextmanager from settings import web_driver @contextmanager def ContextDriver(): try: yield web_driver finally: web_driver.close()
Аккуратно, не так ли? На самом деле, я впервые написал этот Context Manager через декоратор, когда столкнулся с этой проблемой на работе. И потратил некоторое время на то, чтобы переписать его как класс для этой статьи. Это не означает, что вы должны знать только, как это сделать с помощью декоратора, хотя это намного проще. Бывают случаи, когда вам понадобится класс, и в одной из следующих статей я покажу это.
И есть еще один способ определить контекстный менеджер. Просто импортируйте закрытие и используйте with closing(driver) as…
Это работает со всем, что имеет метод close()
. Но я не большой любитель этого.
Итак, теперь вы знаете, зачем и как использовать контекстный менеджер! Но просто знать недостаточно. Попробуйте это в своем следующем проекте. Или даже в вашем нынешнем! Таким образом, вы будете уверены, что можете реализовать это везде, где это подходит. Кроме того, это одна из тем, о которых любят спрашивать технические интервьюеры.
Вы также можете найти эту и другие статьи в моем блоге на github.