Рубрики
Без рубрики

Python с заявлением и контекстными менеджерами

Узнайте о контекстных менеджерах Python, модуль Contextlib и Python с заявлением в этой статье от Mike Driscoll

Автор оригинала: Mike Driscoll.

Python вышел с особым новым ключевым словом несколько лет назад в Python 2.5, который известен как с утверждение. Это новое ключевое слово позволяет разработчику создавать контекстные менеджеры. Но ждать! Что такое контекстный менеджер? Они удобные конструкции, которые позволяют вам что-то устанавливать и разорвать что-то автоматически. Например, вы можете открыть файл, написать кучу материал к нему, а затем закрыть его. Это, вероятно, классический пример контекстно-менеджера. На самом деле, Python автоматически создает один для вас, когда вы открываете файл, используя с утверждение:

with open(path, 'w') as f_obj:
    f_obj.write(some_data)

Вернуться в Python 2.4, вам придется сделать это старомодный путь:

f_obj = open(path, 'w')
f_obj.write(some_data)
f_obj.close()

То, как это работает под крышками, с использованием некоторых магических методов Python: __enter__ и __exit__ Отказ Попробуем создать свой собственный менеджер контекста, чтобы продемонстрировать, как это все работает!

Создание класса менеджера контекста

Вместо того, чтобы переписать открытый метод Python здесь, вы создадите менеджер контекста, который может создать подключение к базе данных SQLite и закрыть его, когда это сделано. Вот простой пример:

import sqlite3


class DataConn:
    """"""

    def __init__(self, db_name):
        """Constructor"""
        self.db_name = db_name

    def __enter__(self):
        """
        Open the database connection
        """
        self.conn = sqlite3.connect(self.db_name)
        return self.conn

    def __exit__(self, exc_type, exc_val, exc_tb):
        """
        Close the connection
        """
        self.conn.close()
        if exc_val:
            raise

if __name__ == '__main__':
    db = '/home/mdriscoll/test.db'
    with DataConn(db) as conn:
        cursor = conn.cursor()

В вышеупомянутом коде вы создали класс, который передает путь к файлу базы данных SQLite. __enter__ Способ выполняется автоматически, где он создает и возвращает объект подключения к базе данных. Теперь, когда у вас есть, вы можете создать курсор и записывать в базу данных или запросить его. Когда вы выходите из с Заявление, это вызывает __exit__ Способ выполнить и это закрывает соединение.

Попробуем создать менеджер контекста, используя другой метод.

Создание менеджера контекста с использованием ContextLib

Python 2.5 не только добавлен с заявление, но он также добавил Contextlib модуль. Это позволяет создать менеджер контекста, используя Contextlib ContextManager Функция как декоратор.

Давайте попробуем создать контекстный менеджер, который открывается и закрывает файл в конце концов:

from contextlib import contextmanager

@contextmanager
def file_open(path):
    try:
        f_obj = open(path, 'w')
        yield f_obj
    except OSError:
        print("We had an error!")
    finally:
        print('Closing file')
        f_obj.close()

if __name__ == '__main__':
    with file_open('/home/mdriscoll/test.txt') as fobj:
        fobj.write('Testing context managers')

Здесь вы импортируете ContextManager от Contextlib и украсить ваш file_open () функционировать с этим. Это позволяет звонить file_open () Использование Python’s с утверждение. В вашей функции вы открываете файл, а затем доходность Это так, чтобы вызывающая функция может использовать ее.

Однажды с Заявление о заявлении, контроль возвращается обратно в file_open () и он продолжается с кодом, следуя за доходность утверждение. Это вызывает Наконец Заявление для выполнения, который закрывает файл. Если у вас есть Осэррор Работая с файлом, он пойман, а Наконец Заявление все еще закрывает обработчик файла.

contextlib.closing ()

Модуль Contextlib поставляется с другими удобными утилитами. Первый – это закрытие Класс, который закроет вещь на завершение блока кода. Документация Python дает пример, который аналогичен следующему:

from contextlib import contextmanager

@contextmanager
def closing(db):
    try:
        yield db.conn()
    finally:
        db.close()

В основном то, что вы делаете, является создание функции закрытия, которая завернута в ContextManager Отказ Это эквивалент того, что делает класс закрытия. Разница в том, что вместо декоратора вы можете использовать закрытие Сам класс в вашем с заявлением.

Вот что это будет выглядеть:

from contextlib import closing
from urllib.request import urlopen

with closing(urlopen('http://www.google.com')) as webpage:
    for line in webpage:
        # process the line
        pass

В этом примере вы открываете URL, но оберните его своим классом закрытия. Это приведет к тому, что ручка на веб-странице будет закрыта, как только вы выпадете из с Заявление о кодовом блоке.

contextlib.suppress (* исключения)

Еще один удобный маленький инструмент – подавить Класс, который был добавлен в Python 3.4. Идея этой утилиты контекстно-менеджера заключается в том, что он может подавлять любое количество исключений. Общий пример, когда вы хотите игнорировать FileNotfoundError исключение. Если вы должны были написать следующий менеджер контекста, он не будет работать:

>>> with open('fauxfile.txt') as fobj:
        for line in fobj:
            print(line)

Traceback (most recent call last):
  Python Shell, prompt 4, line 1
builtins.FileNotFoundError: [Errno 2] No such file or directory: 'fauxfile.txt'

Этот менеджер контекста не обрабатывает это исключение. Если вы хотите игнорировать эту ошибку, вы можете сделать следующее:

from contextlib import suppress

with suppress(FileNotFoundError):
    with open('fauxfile.txt') as fobj:
        for line in fobj:
            print(line)

Здесь вы импортируете подавить и пропустите его исключение, которое вы хотите игнорировать, что в этом случае является FileNotfoundError исключение. Если вы запустите этот код, ничего не происходит, так как файл не существует, но ошибка также не поднимается. Следует отметить, что этот контекстный менеджер является ReentRant Отказ Это будет объяснено позже в этой статье.

contextlib.redirect_stdout/redirect_stderr.

Библиотека Contextlib имеет пару аккуратных инструментов для перенаправления Stdout и Stderr, которые были добавлены в Python 3.4 и 3.5 соответственно. Прежде чем эти инструменты были добавлены, если вы хотите перенаправить Stdout, вы сделаете что-то подобное:

path = '/path/to/text.txt'

with open(path, 'w') as fobj:
    sys.stdout = fobj
    help(sum)

С Contextlib Модуль, теперь вы можете сделать следующее:

from contextlib import redirect_stdout

path = '/path/to/text.txt'
with open(path, 'w') as fobj:
    with redirect_stdout(fobj):
        help(redirect_stdout)

В обоих этих примерах вы перенаправляете stdout к файлу. Когда вы называете Python’s Помощь () вместо печати на stdout он сохраняется непосредственно в файл. Вы также можете перенаправить stdout к какому виду буфера или виджета типа управления текстовым элементом от инструментария пользовательского интерфейса, такого как TKinter или WxPython.

ExitStack.

ExitStack Является ли менеджер контекста, который позволит вам легко программно объединить другие контекстные менеджеры и функции очистки. Сначала звучит вид с толку, поэтому давайте посмотрим на примере документации Python, чтобы помочь вам понять эту идею немного лучше:

>>> from contextlib import ExitStack
>>> with ExitStack() as stack:
        file_objects = [stack.enter_context(open(filename))
            for filename in filenames]
                    ]

Этот код в основном создает ряд контекстных менеджеров внутри понимания списка. ExitStack Поддерживает стопку зарегистрированных обратных вызовов, которые оно позвонит в обратном порядке, когда экземпляр закрыт, что происходит при выходе из нижней части с утверждение.

В документации Python есть куча аккуратных примеров для Contextlib Где вы можете узнать о темах, таких как следующее:

  • Уловить исключения из методов __enter__
  • Поддерживает переменное количество контекстных менеджеров
  • Замена любого использования попробовать
  • и многое другое!

Вы должны проверить это, чтобы вы получили хорошее почувствовать, насколько мощный этот класс.

Обертывание

Контекстные менеджеры очень веселые и все время пригодятся. Я использую их в моих автоматизированных тестах все время для открытия и закрытия диалогов. Теперь вы должны быть в состоянии использовать встроенные инструменты Python для создания собственных контекстных менеджеров. Обязательно найдите время, чтобы прочитать документацию Python в ContextLib, поскольку есть много дополнительной информации, которая не распространяется в этой главе. Весело и счастливое кодирование!