10

假设我们有一个类“A”,它本身就充当上下文管理器,所以它实现了

def __enter__()
def __exit__()

界面。客户端代码直接使用with语句生成“A”对象是有效的。

现在,我们还有另一个类“B”,它封装了其他功能,也使用了“A”对象。

如果我们也想让“B”充当上下文管理器,那么管理它的“A”实例的正确方法是什么?

是否应该在“B”上调用__enter__和(分别)调用它的 A 对象实例?或者,还有更好的方法?__exit____enter____exit__

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

  • DatabaseConnection
  • DatabaseConnectionPool

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

DatabaseConnectionPool使用了几个DatabaseConnections以及其他一些零碎的东西。使用DatabaseConnectionPool(即“with”)应该对它的实例进行设置和拆除DatabaseConnection(以及它可能想做的任何其他事情)

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

在 Outer 上调用 Enter
在 Inner 上调用 Enter
在外部环境中...
do_foo 调用!
还在用外...
在内部调用退出
在外部调用的退出
使用外部完成

但我得到以下信息:

在 Outer 上调用 Enter
在 Inner 上调用 Enter
在内部调用退出
在外部环境中...
do_foo 调用!
还在用外...
在外部调用的退出
使用外部完成

代码:


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"

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

4

2 回答 2

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
于 2014-06-16T00:29:10.137 回答
0

FWIW,我有相同的设计考虑,最终在我的“子”类中编写了退出和输入函数,并且只有“父”类是上下文管理器。

(如果我正确理解了您的问题,那就是'当我关闭父上下文管理器时,我如何才能优雅地让我在上下文管理器类中使用的所有类也正确关闭)

于 2022-02-21T22:39:27.543 回答