Mic*_*all 28 python exception-handling with-statement contextmanager
我希望将数据库事务的逻辑封装到一个with块中; 将代码包装在事务中并处理各种异常(锁定问题).这很简单,但是我想让块在某些异常后封装代码块的重试.我无法看到一种方法将它整齐地打包到上下文管理器中.
是否可以在with语句中重复代码?
我想像它一样使用它,这真的很整洁.
def do_work():
...
# This is ideal!
with transaction(retries=3):
# Atomic DB statements
...
...
Run Code Online (Sandbox Code Playgroud)
我目前正在使用装饰器处理它,但我更愿意提供上下文管理器(或实际上两者),所以我可以选择在with块中包含几行代码而不是包装在装饰器中的内联函数,这就是我现在所做的:
def do_work():
...
# This is not ideal!
@transaction(retries=3)
def _perform_in_transaction():
# Atomic DB statements
...
_perform_in_transaction()
...
Run Code Online (Sandbox Code Playgroud)
小智 13
是否可以在
with语句中重复代码?
正如之前在邮件列表线程中指出的那样,您可以通过使装饰器调用传递的函数来减少一些重复:
def do_work():
...
# This is not ideal!
@transaction(retries=3)
def _perform_in_transaction():
# Atomic DB statements
...
# called implicitly
...
Run Code Online (Sandbox Code Playgroud)
我这样做的方法只是实现一个标准的数据库事务上下文管理器,但允许它retries在构造函数中接受一个参数.然后我将在你的方法实现中将其包装起来.像这样的东西:
class transaction(object):
def __init__(self, retries=0):
self.retries = retries
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, traceback):
pass
# Implementation...
def execute(self, query):
err = None
for _ in range(self.retries):
try:
return self._cursor.execute(query)
except Exception as e:
err = e # probably ought to save all errors, but hey
raise err
with transaction(retries=3) as cursor:
cursor.execute('BLAH')
Run Code Online (Sandbox Code Playgroud)
由于装饰器本身就是函数,因此您可以执行以下操作:
with transaction(_perform_in_transaction, retries=3) as _perf:
_perf()
Run Code Online (Sandbox Code Playgroud)
有关详细信息,您需要实现transaction()为工厂方法,该方法返回一个带有__callable__()set 的对象来调用原始方法并在失败时重复最多retries次数;__enter__()并将__exit__()被定义为数据库事务上下文管理器的正常情况。
您也可以进行设置transaction(),使其本身执行传递的方法最多retries次数,这可能需要与实现上下文管理器相同的工作量,但意味着实际使用量将减少到仅transaction(_perform_in_transaction, retries=3)(事实上, ,相当于 delnan 提供的装饰器示例)。
| 归档时间: |
|
| 查看次数: |
4329 次 |
| 最近记录: |