基于公共lisp的重启条件系统的pythonisation

withrestart的Python项目详细描述


withrestart:使用命名的重新启动函数进行结构化错误恢复

这是对 基于重启的通用lisp状态系统。它是用来制造错误的 通过消除未处理错误的假设,恢复变得越来越简单 一定是致命的。

“restart”表示用于恢复函数执行的命名策略 错误发生后。在执行期间的任何时候 函数可以将restart对象推送到其调用堆栈上。如果有例外 在重新启动的范围内发生,调用链中较高的代码可以 调用它以从错误中恢复并让函数继续执行。 通过提供几个重新启动,函数可以提供几个不同的策略 从错误中恢复。

“处理程序”表示处理事件的更高级别策略 一个错误。它在概念上类似于“except”子句 建立一套处理程序对象,如果在 一些代码的执行。然而,有一个关键的区别:处理者 在不展开调用堆栈的情况下执行。因此他们有机会 采取纠正措施,然后恢复执行任何功能 引发了错误。

例如,考虑一个函数,它从 目录到内存中的dict中:

def readall(dirname):
    data = {}
    for filename in os.listdir(dirname):
        filepath = os.path.join(dirname,filename)
        data[filename] = open(filepath).read()
    return data

如果在调用os.listdir()之后丢失了其中一个文件,则 后续的open()将引发ioerror。我们可以抓住并处理 此函数中有错误,应该采取什么措施?应该 丢失的文件会被忽略吗?是不是应该用 一些默认内容?如果在 数据字典?什么价值?readAll()函数没有足够的 决定适当恢复策略的信息。

相反,readall()可以提供infrastructure来执行错误恢复 最后的决定权在呼叫代码上。以下定义 使用三个预定义的重新启动来让调用代码(a)跳过丢失的 文件完全,(2)在采取一些纠正措施后重试对open()的调用 操作,或(3)使用其他值代替丢失的文件:

def readall(dirname):
    data = {}
    for filename in os.listdir(dirname):
        filepath = os.path.join(dirname,filename)
        with restarts(skip,retry,use_value) as invoke:
            data[filename] = invoke(open,filepath).read()
    return data

这里需要注意的是使用“with”语句来建立一个新的上下文 在重新启动的范围内,并在调用 可能失败的函数。后者允许重新启动以注入备用 失败函数的返回值。

下面是如果调用代码想悄悄跳过 缺少文件:

def concatenate(dirname):
    with Handler(IOError,"skip"):
        data = readall(dirname)
    return "".join(data.itervalues())

这会将处理程序实例推送到执行上下文中,执行上下文将检测 ioerror实例并通过调用“skip”重启点进行响应。如果这个 处理程序是响应ioerror调用的,执行readAll() 函数将在“with restarts(…)”块之后立即继续。

请注意,无法使用 普通的try-except块;当ioerror传播到 concatenate()函数用于处理,执行 readAll()将被解除绑定,无法继续。

调用希望重新创建丢失文件的代码只需将 不同的错误处理程序:

def concatenate(dirname):
    def handle_IOError(e):
        open(e.filename,"w").write("MISSING")
        raise InvokeRestart("retry")
    with Handler(IOError,handle_IOError):
        data = readall(dirname)
    return "".join(data.itervalues())

通过提升invokerestart,这个处理程序将控制权传递回restart 由readAll()函数建立的。这次重新启动 将重新执行失败的函数调用,并让readAll()继续其 操作。

调用希望使用特殊sentinel值的代码将使用处理程序 要将所需值传递给“使用值”,请重新启动:

def concatenate(dirname):
    class MissingFile:
        def read():
            return "MISSING"
    def handle_IOError(e):
        raise InvokeRestart("use_value",MissingFile())
    with Handler(IOError,handle_IOError):
        data = readall(dirname)
    return "".join(data.itervalues())

通过将从错误中恢复的低级细节从 采取什么行动的高层战略有可能创造出 强大的恢复机制。

虽然此模块提供了一些预构建的重新启动,但函数将 通常都想自己创造。这可以通过传递回调来完成 进入重新启动对象构造函数:

def readall(dirname):
    data = {}
    for filename in os.listdir(dirname):
        filepath = os.path.join(dirname,filename)
        def log_error():
            print "an error occurred"
        with Restart(log_error):
            data[filename] = open(filepath).read()
    return data

或者使用decorator定义内联重新启动:

def readall(dirname):
    data = {}
    for filename in os.listdir(dirname):
        filepath = os.path.join(dirname,filename)
        with restarts() as invoke:
            @invoke.add_restart
            def log_error():
                print "an error occurred"
            data[filename] = open(filepath).read()
    return data

处理程序也可以使用类似的语法内联定义:

def concatenate(dirname):
    with handlers() as h:
        @h.add_handler
        def IOError(e):
            open(e.filename,"w").write("MISSING")
            raise InvokeRestart("retry")
        data = readall(dirname)
    return "".join(data.itervalues())

最后,是免责声明。我从来没有写过任何普通的口齿不清。我只看过 关于常见的lisp条件系统以及它有多棒。我肯定有 有很多事情是它可以做的,而这个模块根本做不到。例如:

  • Since this is built on top of a standard exception-throwing system, the handlers can only be executed after the stack has been unwound to the most recent restart context; in Common Lisp they’re executed without unwinding the stack at all.
  • Since this is built on top of a standard exception-throwing system, it’s probably too heavyweight to use for generic condition signalling system.

然而,当你看到一个好主意的时候,捏一个好主意并不羞耻……

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java中char的用途   swing修复,以便显示可以同时显示十进制数和整数   java给定一个场景,找到拥有的JFXPanel   java JPA 2标准获取路径导航   java如何用JUnit测试这个类?   JSF中的java请求作用域   Spring云Zuul代理背后的java Spring OAuth授权服务器   java限制聚合返回的存储桶大小   java如何在安卓应用程序中请求超级su权限   防止超级关键字的java Checkstyle规则   java 安卓。应用程序。应用程序无法强制转换到安卓。应用程序。在回收器适配器中使用FragmentManager时的活动   使用Java的Twitter广告API   切换到4.0.1版本后,java“JavaMailSenderImpl无法解析为类型”   java没有getter方法可用于名称下bean的属性   java 0/1背包堆空间   java我无法使用断点进行调试   Jar文件名表单java代码   java调用从扩展活动的MainActivity类扩展片段的类片段