我想知道长期运行的函数中是否存在处理错误的Python方式,这种错误可能部分地影响了函数的继续执行能力。
例如,考虑一个给定URL列表的函数,该函数以递归方式检索顶级URL路径下的资源和所有链接的资源。它将检索到的资源存储在本地文件系统中,该文件系统具有与URL结构类似的目录结构。本质上,这是页面列表的基本递归wget。
该功能可能会在很多方面失败:
检索或保存任何一种资源失败只会影响函数继续处理该资源以及可能与之链接的任何子资源的能力,但是可以继续检索其他资源。
错误处理的简单模型是,在第一个错误时,会引发适当的异常以供调用者处理。问题在于它终止了该功能并且不允许其继续运行。该错误可能已修复,并且该功能从头开始重新启动,但这将导致工作重做,并且任何永久性错误都可能意味着我们永远无法完成。
我想到的一些替代方法是:
在Python讨论中,我经常注意到某些描述为Pythonic或非Pythonic的方法。我想知道是否有任何特别的Python方法来处理上述场景类型。
Python是否附带了比异常处理的终止模型更复杂的错误处理模型,或者是否更复杂的电池使用了我应该复制以保持Pythonic的错误处理模型?
注意:请不要专注于示例。我不是要解决该特定领域中的问题,但是这似乎是一个很好的例子,大多数人在这里都可以理解。
最佳答案
我认为您在此处所讨论的级别没有特别明显的“Pythonic/非Pythonic”区别。
在此领域中没有“一刀切”的重要原因之一是,您想要的确切语义将是针对特定问题的。
甚至支持错误处理程序也不一定能涵盖所有这些所需的行为-一个简单的每次故障错误处理程序也无法轻松提供中止和回滚语义,或者最终不会产生单个异常。 (这并非不可能-您只需要弄懂诸如将绑定(bind)方法或闭包作为错误处理程序传递之类的技巧即可)
因此,您最好的办法是对典型的使用场景和遇到错误时的预期行为进行有根据的猜测,然后相应地设计API。
完全通用的解决方案将接受一个错误处理程序,该错误处理程序会在发生每个错误时得到处理,而最终的“错误已发生”处理程序将为调用者提供一个机会来决定如何处理多个错误(使用某种协议(protocol)允许数据被处理)。从各个错误处理程序传递到最终批处理错误处理程序)。
但是,提供这种通用解决方案可能是API设计失败。 API的设计者应该对如何使用他们的API以及应该如何处理错误有意见。要记住的主要事情是不要过度设计您的解决方案:
作为一般原则,您可能会得到的最好的结果是,“Pythonic”错误处理将尽可能简单,但没有那么简单。但是到那时,这个词只是被用作“好代码”的同义词,这实际上并不是它的意图。
另一方面,谈论非Pythonic错误处理可能采用的实际形式稍微容易一些:
def myFunction(an_arg, error_handler)
# Do stuff
if err_occurred:
if isinstance(err, RuntimeError):
error_handler.handleRuntimeError()
elif isinstance(err, IOError):
error_handler.handleIOError()
Python的惯用法是,如果根本支持错误处理程序,那么它们只是简单的可调用对象。给他们提供他们决定如何处理情况所需的信息,而不是代表他们做出太多决定。如果要使实现错误处理的常见方面更容易,请提供一个单独的帮助程序类,该类具有进行分派(dispatch)的
__call__
方法,以便人们可以决定是否要使用它(或要使用多少)。当他们确实使用它时覆盖)。这并不完全是特定于Python的,但这是来自语言的人的烦人之处,这使得烦人地难以传递任意可调用对象(例如Java,C,C++)可能会出错。因此,复杂的错误处理协议(protocol)无疑是进入“非Pythonic错误处理”领域的一种方式。上面的非Pythonic代码中的另一个问题是没有提供默认处理程序。迫使每个API用户做出他们可能还没有能力做出的决定,只是API设计不佳。但是现在我们回到了一般的“好代码”/“坏代码”领域,因此实际上不应使用Pythonic/非Pythonic来描述两者之间的区别。
关于error-handling - 复杂功能的Pythonic错误处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5535421/