我有一个非常常见的代码模式:
if not resource.hasInstallTag(tag="mysoftwareservice", version="5"):
doX()
doY()
frobnicate()
do()
installMySoftwareService()
resource.recordInstallTag(tag="mysoftwareservice", version="5")
然而,在一个地方更新版本字符串并忘记在另一个地方执行此操作非常容易,或忘记忘记将调用添加到recordInstallTag。
我希望有类似以下的模式:
with InstallTag(resource, tag, version):
doX()
installTheThingThat(version)
doY()
frobnicate()
其中:
例如:
class TagAlreadySetException(Exception):
pass
class InstallTag(object):
def __init__(self, resource, tag, version):
self.resource = resource
self.tag = tag
self.version = version
def __enter__(self):
if self.resource.hasInstallTag(self.tag, self.version):
# Prevent execution of statement block
raise TagAlreadySetException()
return None
def __exit__(self, type, value, tb):
if type==None:
self.resource.recordInstallTag(self.tag, self.version)
不幸的是,虽然提高TagAlreadySetException会阻止执行语句块,但它也会继续将异常抛出调用堆栈。我想捕获TagAlreadySetException并处理它。我可以在没有额外额外机制的情况下执行此操作吗?
我意识到我可以尝试......最后。但是,我试图确保标签和项目只在应用模式时写入一次(以防止出现不一致)
答案 0 :(得分:1)
这是一个整洁的小伙伴:
import contextlib
def manager_gen(resource, tag, version):
def check():
check.called = True
if resource.hasInstallTag(tag, version):
raise TagAlreadySetException
check.called = False
try:
yield check
except TagAlreadySetException:
pass
finally:
if not check.called:
raise RuntimeError("check wasn't called!")
InstallTag = contextlib.contextmanager(manager_gen)
你会像这样使用它:
with InstallTag as checker:
checker()
raz_the_jazz_and_other_neat_statements()
如果您忘记运行检查,它会在块结束时向您大喊(可能有用也可能没用......)