如何将子上下文的管理委托给父

时间:2014-06-15 23:42:04

标签: python contextmanager

我们说我们上了一堂课' A'它本身就是一个上下文管理器,所以它实现了

def __enter__()
def __exit__()

接口。它对客户端代码有效,可以使A' A'对象直接使用with语句。

现在,我们还有另一个班级' B'它封装了其他功能,并使用了A'宾语。

如果我们想要' B'作为一个上下文管理器,以及管理它的正确方法' A'实例

{' B'上的__enter____exit__的实施是否应该在它的A对象实例上分别调用__enter____exit__?或者有更好的方法吗?

举一个具体的例子(这是不是我在我的应用程序中使用的东西,它只是我想到的第一个非抽象的例子)考虑两个类

  • DatabaseConnection
  • DatabaseConnectionPool

在其上使用单个DatabaseConnection是有效的,因此DatabaseConnection实现了上下文管理器接口。

DatabaseConnectionPool使用了几个DatabaseConnections以及其他位和bob。使用DatabaseConnectionPool(即&#34;使用&#34;)应该对其DatabaseConnection个实例进行设置和拆除(以及其他可能要做的事情)< / p>

更新:我已经编写了一些测试代码,我希望它能提供以下输出:

Enter invoked on Outer
Enter invoked on Inner
Within outer context...
do_foo invoked!
Still using outer...
Exit invoked on inner
Exit invoked on outer
Done using outer

但我得到以下内容:

Enter invoked on Outer
Enter invoked on Inner
Exit invoked on inner
Within outer context...
do_foo invoked!
Still using outer...
Exit invoked on outer
Done using outer

代码:


class Inner(object):
  def __enter__(self):
    print "Enter invoked on Inner"
    return self

  def __exit__(self, typ, val, tb):
    print "Exit invoked on inner"

  def do_foo(self):
    print "do_foo invoked!"

class Outer(object):
  def __init__(self):
    self._inner = Inner()

  def __enter__(self):
    print "Enter invoked on Outer"

    with self._inner as ctx:
      return self

  def __exit__(self, typ, val, tb):
    print "Exit invoked on outer"

with Outer() as outer:
  print "Within outer context..."
  outer._inner.do_foo()
  print "Still using outer..."

print "Done using outer"

关于如何使这项工作的任何想法?

1 个答案:

答案 0 :(得分:0)

这真的是一个设计问题和判断电话。我将提出以下建议:

池类实例提供上下文,然后根据需要以编程方式使用数据库连接实例。但这比为每个数据库实例简单地调用__enter____exit__要复杂一些,而且我认为你不应该尝试这样做,他们并不打算这样做那个目的。在这种情况下,我建议直接使用数据库实例的上下文管理器。

如果你想使用他们的上下文管理器,这样的东西会起作用:

def __enter__(self):
    for db in self.pool:
        with db as d:
            d.transaction()

def __exit__(self, type, value, traceback):
    pass 

但是如果你想自己错误处理:

def __enter__(self):
    for db in self.pool:
        try:
            db.connection()
            # ... write and transact here

def __exit__(self, type, value, traceback):
    if type is None: # no errors, so close as normal
        for db in self.pool:
            db.close()
    # ... more code here for proper error handling