edd*_*uld 7 python contextmanager
假设我们有一个类“A”,它本身就充当上下文管理器,因此它实现了
def __enter__()
def __exit__()
Run Code Online (Sandbox Code Playgroud)
界面。客户端代码直接使用with语句创建“A”对象是有效的。
现在,我们还有另一个类“B”,它封装了其他功能,并使用了“A”对象。
如果我们还想让“B”充当上下文管理器,那么管理它的“A”实例的正确方法是什么?
如若实施__enter__,并__exit__于“B”的呼叫__enter__,并__exit__在其上的一个对象实例(分别)?或者,还有更好的方法?
举一个具体的例子(这不是我在我的应用程序中使用的,这只是我想到的第一个非抽象例子)考虑两个类
DatabaseConnectionDatabaseConnectionPool单独使用单个是有效DatabaseConnection的,因此DatabaseConnection实现了上下文管理器接口。
DatabaseConnectionPool使用几个DatabaseConnections以及其他位和鲍勃。使用DatabaseConnectionPool(即“with”)应该对它的DatabaseConnection实例进行设置和拆除(以及它可能想做的任何其他事情)
更新: 我写了一些测试代码,我希望能给出以下输出:
在外部调用输入 在内部调用输入 在外部环境中... do_foo 调用了! 还在用外... 在内部调用退出 在外部调用退出 使用外部完成
但我得到了以下信息:
在外部调用输入 在内部调用输入 在内部调用退出 在外部环境中... 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"
Run Code Online (Sandbox Code Playgroud)
关于如何使这项工作的任何想法?
这实际上是一个设计问题和一个判断。我将提出以下建议:
Pool 类实例提供一个上下文,然后根据需要以编程方式使用数据库连接实例。__enter__但这比简单地为每个数据库实例调用and稍微复杂一些__exit__,我认为您不应该尝试这样做,它们并不是用于此目的。在这种情况下,我建议直接使用数据库实例的上下文管理器。
如果你想使用他们的上下文管理器,像这样的东西会起作用:
def __enter__(self):
for db in self.pool:
with db as d:
d.transaction()
def __exit__(self, type, value, traceback):
pass
Run Code Online (Sandbox Code Playgroud)
但如果你想自己处理错误:
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
Run Code Online (Sandbox Code Playgroud)