如何使用我的自定义异常处理类重写异常消息



如何在MyException的方法中捕获同名异常并运行MyException中定义的相应方法?因为我想带有错误代码和错误消息的rewrite the error message

class OrmError:
# catch django orm process error
pass
class SysError:
def IndexError(self):
print("index error, you need to ...")
def SomeError1(self):
print('something1')
def SomeError2(self):
print('something2')
class OtherError:
pass
class MyException(OrmError, SysError, OtherError):
# do something
pass

try:
lis = []
a = lis[1]
except MyException:
# how to catch the exception which have the same name in MyException's method 
# and run the corresponding method defined in MyException, because i want to 
# rewrite the error message
pass
except Exception as e:
# print uncaught error
print(e)

您可以尝试以下操作:

class MyException(Exception):
def IndexError(self):
print("index error, you need to ...")

def SomeError1(self):
print('something1')

def SomeError2(self):
print('something2')
try:
lis = []
a = lis[1]
except Exception as e:
error_name = e.__class__.__name__
if error_name in dir(MyException):
# If error is handled in custom MyException
ex = MyException()
ex_function = getattr(ex, error_name)
ex_function()
else:
# Otherwise, print default error message
print(e)

e.__class__.__name__为您提供了引发的异常类型,然后您可以使用它来检查它是否在自定义类中定义/处理。

以这种方式使用类是对有效工具的滥用。您并没有试图在这里封装任何内容。对于要转换的每个异常都有一个单独的方法,这一想法很好,但您缺少了查找异常类型的方法。

编辑内置异常消息的最简单方法是修改args属性:

try:
enumerate(1)
except Exception as e:
print(e.args)
e.args = (e.args[0].replace('not ', ''),)
raise

结果是

("'int' object is not iterable",)
Traceback (most recent call last):
File "<ipython-input-131-740297d24fb6>", line 1, in <module>
try: enumerate(1)
TypeError: 'int' object is iterable

下一步是提供一种识别异常并映射其消息的方法。您可以执行与一系列except块类似的操作:按照要捕获的顺序提供要捕获的异常的列表,并提供一个可调用的对象来转换每个异常。顺序很重要,所以您可以使用列表,也可以使用OrderedDict。在python 3.6+中,常规dict是有序的,但我在这里不依赖于此功能。

您可以通过多种方式转换异常。可调用程序可以接受异常对象或字符串。它们可以返回异常对象或字符串,也可以什么都不返回。我建议摄入一种无回报的食物。这是因为在except子句中引发特定的异常对象,即使是触发该子句的同一异常,也会重新启动回溯。将上面的片段与下面的片段进行比较:

try:
enumerate(1)
except Exception as e:
print(e.args)
e.args = (e.args[0].replace('not ', ''),)
raise e

请注意,错误的来源不再是enumerate行:

("'int' object is not iterable",)
Traceback (most recent call last):
File "<ipython-input-134-b1123bf70859>", line 6, in <module>
raise e
File "<ipython-input-134-b1123bf70859>", line 2, in <module>
enumerate(1)
TypeError: 'int' object is iterable

所以你可以写这样的东西:

from collections import OrderedDict
def handleIndexError(e):
e.args = ('You need to work on the size of your index',)
def handleMyCustomError(e):
e.args = (f'Really, be more careful: some attribute {e.attr} needs to be better',)
def handleBadException(e):
e.args = (f'This is a {type(e).__name__} error with message "{e.args[0]}"',)
handler_table = OrderedDict([
(IndexError, handleIndexError),
(MyCustomError, handleMyCustomError),
((MemoryError, OSError), handleBadException)])
def overwrite_exception(exception, table):
for cls, handler in  table:
if isinstance(exception, cls):
return handler(exception)
try:
lis = []
a = lis[1]
except Exception as e:
overwrite_exception(e, handler_table)
raise

请注意,如果您想像普通异常处理程序那样使用isinstance功能,OrderedDictlist相比并没有太大优势。如果您想匹配精确的类而不是使用isinstance,则不需要排序,而使用普通的dict即可。在这种情况下,您必须在单独的键中列出每种类型。通常,isinstance将接受元组,如上面所示的handler_table的最后一个键。

让您的处理程序接受完整异常对象的原因是,并非所有异常都会使用args作为其str表示(甚至有args属性(。如果您遇到使用不同机制创建字符串表示的类型,则拥有完整异常对象将允许您适应它。

另外,不要忘记sys.exc_info,它可以用来收集关于对象本身中无法直接获得的异常的信息。

我可以通过以下方式实现我的目标,但我认为这并不优雅。有更好的方法吗?

class OrmHandlelException(object):
def IntegrityError(self):
print('Integrity error')

# there may be many other type of exception 
# which i also want to classify with independent class        
class OtherException(object):
pass      

class MyExceptionHandler(OrmHandlelException, OtherException):
def __call__(self, error):
error_handle_method = getattr(self, type(error).__name__, None)
if error_handle_method is not None:
error_handle_method()
else:
print(error)

my_exception_handler = MyExceptionHandler()    
try:
print('do something here')
lis = []
a = lis[1]
except Exception as error:
my_exception_handler(error)

最新更新