如何从习惯用法在Python对象方法打开多个管理资源

问题描述 投票:1回答:1

什么是构造一个对象以打开多个(情境管理)资源,也与这些资源工作的最Python的方式?

我有打开多个管理资源,然后在类中的方法操作的一类。

例如,如果我不得不打开在同一时间到本地缓存数据库和Web服务器的连接(例如,检查缓存中的数据,然后再从服务器如果不出现拉)。

我已经能够拿出一些代码来管理使用yield语句的资源,但它似乎并不十分直观。在Python,有没有处理这个问题的一个规范的方法?

Minimal example:

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...

上面的代码看起来做工精细,但它似乎并不十分直观。具体来说,产量在下一个成语似乎有点难以消化。

有没有更好的方法来打开,这将在Python类方法随后用于/关闭多个管理资源?

python resources yield contextmanager
1个回答
1
投票
  1. 我认为,ExitStack会让你的代码更容易
  2. IMO,使用__enter__并明确__exit__next(...)啄更具可读性
  3. 实际上不是有关的CM,但地道的Python代码很大一部分包括命名。 openedclosed全文应该返回布尔不能称为属性,即r.opened -> True。这是大多数人会从你的界面的期望。操作上另一方面,应拼写为动词,像openclose

简单的例子,与上述思路:

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()
© www.soinside.com 2019 - 2024. All rights reserved.