如何验证对象在Python任意版本中是否可被作为异常抛出?
如何验证一个对象是否可作为Python异常抛出?
我最近在项目中需要实现一个工具函数,用来判断给定的参数是否可以被当作异常抛出。最开始写了这样一段代码:
def is_raisable(exception): funcs = (isinstance, issubclass) return any(f(exception, BaseException) for f in funcs)
它能正确处理的场景
这个函数目前可以完美应对两种最常见的情况:
- 检查异常类本身:
is_raisable(KeyError)返回True,因为KeyError是BaseException的直接子类 - 检查已经实例化的异常对象:
is_raisable(KeyError("missing key"))返回True,因为该实例属于BaseException的子类实例
会失效的边缘场景
不过在一些特殊情况下,这个函数的判断会出错或者直接抛出错误:
- 抽象异常基类:如果传入一个继承自
BaseException的抽象基类(ABC),函数会返回True,但实际上你无法实例化并抛出这个类——因为抽象基类要求必须实现抽象方法才能实例化:from abc import ABC, abstractmethod class AbstractAppError(BaseException, ABC): @abstractmethod def log_error(self): pass is_raisable(AbstractAppError) # 返回True,但raise AbstractAppError()会触发TypeError - 异常类型的元组:在
try/except语句中,我们经常会用元组来指定多个要捕获的异常,但如果把这种元组传给is_raisable,函数会直接抛出TypeError——因为issubclass的第一个参数必须是类,不能是元组:is_raisable((KeyError, ValueError)) # 抛出TypeError: issubclass() arg 1 must be a class - 动态修改的类:如果一个原本继承自
BaseException的类被动态修改,移除了继承关系(虽然这种情况很少见),函数的判断结果会和实际可抛出性不一致。
简单的优化思路
如果要覆盖这些场景,可以对函数做一些调整:
- 针对元组的情况,先判断输入是否是元组,然后递归检查每个元素是否可抛出
- 针对抽象基类,可以额外检查该类是否可以被实例化(不过要注意,有些异常类实例化需要必传参数,这种检查可能会有局限性)
内容的提问来源于stack exchange,提问作者Dan Oberlam
相关产品推荐
相关产品推荐

