可以使用with语句来执行和完成条件

2024-06-08 06:09:56 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个非常常见的代码模式:

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()   

其中:

  • 如果资源已将tag==tag安装到version==version,则跳过内部语句块的内容(不引发和异常)
  • (仅限)如果内部语句块无一例外地成功,则记录此版本的项已安装到此资源。你知道吗

例如,类似于:

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并处理它。我能做到这一点没有额外的机器周围我的声明块?你知道吗

我意识到我可以尝试…最后。但是,我试图确保标记和项只在应用模式的地方写入一次(以防止不一致)


Tags: selfifversiondeftagservice模式语句
1条回答
网友
1楼 · 发布于 2024-06-08 06:09:56

这里有一个整洁的小家伙:

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()

如果您忘记运行检查,它会在块的末尾对您大叫(这可能有用,也可能不有用…)你知道吗

相关问题 更多 >

    热门问题