我在继承ContextDecorator
类时遇到问题。我不明白为什么该方法session_manager()
有效:
@contextmanager
def session_manager():
session = Session()
yield session
try:
session.commit()
except Exception as e:
session.rollback()
raise e
finally:
session.close()
但是与ContextDecorator
后继类完全相同的代码给出了错误:
class SessionManager(ContextDecorator):
def __init__(self):
self.session = Session()
def __enter__(self):
try:
yield self.session
self.session.commit()
except Exception as e:
self.session.rollback()
raise e
def __exit__(self, *exc):
self.session.close()
例外:
AttributeError: 'generator' object has no attribute 'add'
文档和教程没有复杂的示例(仅使用“打印”语句),并且效果很好:https : //docs.python.org/3/library/contextlib.html
我不明白为什么方法session_manager()
有效,尽管它返回一个生成器:
yield session
这里我写了一些小而简单的代码:https : //gist.github.com/tranebaer/46f94263030dd8f7c1bfcf72d0e37610
该__enter__
方法不应该是生成器,除非您想在运行时上下文中这样处理返回值。当进入由 with- 语句控制的块时调用它,并且它的返回值绑定到as
子句中指定的目标(如果有)。所以属性错误是在add()
块内的生成器上调用方法的结果,当你的意思是它是Session
对象时。可能的清理和异常处理应该在__exit__
方法中进行:
from contextlib import closing, ContextDecorator, ExitStack
class SessionManager(ContextDecorator):
def __init__(self, session_cls=Session):
self.session = session_cls()
def __enter__(self):
return self.session
def __exit__(self, type, value, tb):
with closing(self.session), ExitStack() as stack:
stack.callback(self.session.rollback)
if not value:
self.session.commit()
# If commit raises an exception, then rollback is left
# in the exit stack.
stack.pop_all()
请注意,您不需要ContextDecorator
为了创建上下文管理器而继承。仅仅实现__enter__
和__exit__
就够了。实际上在这种情况下它有点毫无意义,因为用 装饰的函数SessionManager
无法访问Session
对象。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句