big*_*ose 128 python polymorphism exception-handling
我正在编写一个模块,并希望为它可以引发的异常建立一个统一的异常层次结构(例如,从一个FooError抽象类继承所有foo模块的特定异常).这允许模块的用户捕获这些特定异常并在需要时明确地处理它们.但是由于其他一些例外,该模块提出的许多例外都被提出; 例如,由于文件上的OSError而导致某些任务失败.
我需要的是"包装"捕获的异常,使其具有不同的类型和消息,以便通过捕获异常的任何信息在传播层次结构中进一步提供信息.但我不想丢失现有的类型,消息和堆栈跟踪; 这对于试图调试问题的人来说都是有用的信息.顶级异常处理程序并不好,因为我试图在异常进入传播堆栈之前修饰异常,并且顶级处理程序为时已晚.
这部分是通过foo从现有类型(例如class FooPermissionError(OSError, FooError))派生模块的特定异常类型来解决的,但这并不会使现有异常实例包装在新类型中更容易,也不会修改消息.
Python的PEP 3134 "异常链接和嵌入式回溯"讨论了Python 3.0中为"链接"异常对象所接受的更改,以指示在处理现有异常期间引发了新的异常.
我正在尝试做的是相关:我需要它也在早期的Python版本中工作,我需要它不是为了链接,而只是为了多态.这样做的正确方法是什么?
big*_*ose 177
Python 3引入了异常链(如PEP 3134中所述).在引发异常时,这允许引用现有异常作为"原因":
try:
frobnicate()
except KeyError as exc:
raise ValueError("Bad grape") from exc
Run Code Online (Sandbox Code Playgroud)
因此,捕获的异常成为新异常的一部分(是"原因"),并且可用于捕获新异常的任何代码.
通过使用此功能,__cause__可以设置属性.内置异常处理程序还知道如何报告异常的"原因"和"上下文"以及回溯.
在Python 2中,看起来这个用例没有好的答案(如Ian Bicking和Ned Batchelder所描述的).游民.
Dev*_*rre 36
您可以使用sys.exc_info()来获取回溯,并使用所述回溯引发新的异常(如PEP所述).如果要保留旧类型和消息,可以在异常上执行此操作,但这仅在异常捕获的任何内容中有用.
例如
import sys
def failure():
try: 1/0
except ZeroDivisionError, e:
type, value, traceback = sys.exc_info()
raise ValueError, ("You did something wrong!", type, value), traceback
Run Code Online (Sandbox Code Playgroud)
当然,这真的没那么有用.如果是,我们就不需要那个PEP.我不建议这样做.
Nik*_*iah 11
class NewException(CaughtException):
def __init__(self, caught):
self.caught = caught
try:
...
except CaughtException as e:
...
raise NewException(e)
Run Code Online (Sandbox Code Playgroud)
但大多数时候,我认为捕获异常,处理raise异常以及原始异常(并保留回溯)或更简单raise NewException().如果我正在调用您的代码,并且我收到了您的一个自定义异常,我希望您的代码已经处理了您必须捕获的任何异常.因此我不需要自己访问它.
编辑:我发现了对抛出自己的异常并保留原始异常的方法的分析.没有漂亮的解决方
我还发现很多时候我需要对引发的错误进行一些“包装”。
这既包含在函数作用域中,有时也只包含函数内的某些行。
创建了一个用于decoratorand的包装器context manager:
import inspect
from contextlib import contextmanager, ContextDecorator
import functools
class wrap_exceptions(ContextDecorator):
def __init__(self, wrapper_exc, *wrapped_exc):
self.wrapper_exc = wrapper_exc
self.wrapped_exc = wrapped_exc
def __enter__(self):
pass
def __exit__(self, exc_type, exc_val, exc_tb):
if not exc_type:
return
try:
raise exc_val
except self.wrapped_exc:
raise self.wrapper_exc from exc_val
def __gen_wrapper(self, f, *args, **kwargs):
with self:
for res in f(*args, **kwargs):
yield res
def __call__(self, f):
@functools.wraps(f)
def wrapper(*args, **kw):
with self:
if inspect.isgeneratorfunction(f):
return self.__gen_wrapper(f, *args, **kw)
else:
return f(*args, **kw)
return wrapper
Run Code Online (Sandbox Code Playgroud)
@wrap_exceptions(MyError, IndexError)
def do():
pass
Run Code Online (Sandbox Code Playgroud)
调用do方法时,不用担心IndexError,只需MyError
try:
do()
except MyError as my_err:
pass # handle error
Run Code Online (Sandbox Code Playgroud)
def do2():
print('do2')
with wrap_exceptions(MyError, IndexError):
do()
Run Code Online (Sandbox Code Playgroud)
inside do2, in context manager, ifIndexError被举起,则会被包裹并举起MyError
| 归档时间: |
|
| 查看次数: |
38859 次 |
| 最近记录: |