Как идиоматически открыть несколько управляемых ресурсов из метода объекта в Python - PullRequest
0 голосов
/ 12 февраля 2019

Какой самый Pythonic способ создания объекта для открытия нескольких (управляемых контекстом) ресурсов и работы с этими ресурсами?

У меня есть класс, который открывает несколько управляемых ресурсов, которые затем обрабатываются вметоды класса.

Например, если мне нужно было одновременно открыть соединение с базой данных локального кэша и веб-сервером (например, сначала проверьте данные в кэше, а затем извлеките их с сервера, если нет).там).

Мне удалось придумать некоторый код для управления ресурсами с помощью оператора yield, но он не кажется очень интуитивным.Есть ли в Python канонический способ решения этой проблемы?

Минимальный пример:

from contextlib import contextmanager

@contextmanager
def resource_A():
    print('opening resource A...')
    a = 'resource_A'
    yield a
    print('closing resource A...')

@contextmanager
def resource_B():
    print('opening resource B...')
    b = 'resource_B'
    yield b
    print('closing resource B...')

class ResourceManager(object):
    def opened(self):
        self.resources = self._resources()
        self.a, self.b = next(self.resources)
    def closed(self):
        try:
            next(self.resources)
        except StopIteration:
            del self.resources
            del self.a
            del self.b
    def _resources(self):
        with resource_A() as a, resource_B() as b:
            yield a, b
    def processing(self):
        print('doing something with resource_A and resource_B...')
    def __enter__(self):
        self.opened()
        return self
    def __exit__(self, ex_type, ex_val, traceback):
        self.closed()

Открытие и закрытие

>>> r = ResourceManager()
>>> r.opened()
opening resource A...
opening resource B...
>>> r.a
'resource_A'
>>> r.b
'resource_B'
>>> r.closed()
closing resource B...
closing resource A...

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

>>> with ResourceManager() as r:
...     r.processing()
...
opening resource A...
opening resource B...
doing something with resource_A and resource_B...
closing resource B...
closing resource A...

Код, приведенный выше, работает нормально, но не очень интуитивно понятен.В частности, идиома yield-next кажется немного трудной для усвоения.

Есть ли лучший способ открыть / закрыть несколько управляемых ресурсов, которые впоследствии будут использоваться в методах класса в Python?

1 Ответ

0 голосов
/ 12 февраля 2019
  1. Я думаю, ExitStack облегчит ваш код
  2. IMO, использование __enter__ и __exit__ явно более читабельно, чем next(...) thingy
  3. На самом деле не о CM, но большая часть идиоматического кода Python включает в себя именование.opened и closed читаются как свойства, которые должны возвращать логическое значение, которые не должны быть вызваны, то есть r.opened -> True.Это то, что большинство людей ожидают от вашего интерфейса. Действия , с другой стороны, должны быть записаны в виде глаголов, как open и close.

Простой пример с идеями выше:

class ResourceManager(object):
    def open(self):
        self.stack = ExitStack()
        self.a = self.stack.enter_context(resource_A())
        self.b = self.stack.enter_context(resource_B())
    def close(self):
        self.stack.close()

    def processing(self):
        print('doing something with resource_A and resource_B...')
    def __enter__(self):
        self.open()
        return self
    def __exit__(self, ex_type, ex_val, traceback):
        self.close()
...