在Python装饰器中引发异常是否是一种很好的模式?
上下文 :我为不同的API端点定义了Flask路由,每个端点使用特定参数(uid,project_id等)调用控制器类。
@app.route('/sample/route', methods=['POST'])
@require_json_payload
@require_fields({
'pid',
'params'
})
def route_handler(arg1, arg2):
#input filtering
...
try:
proj_cntr.sample_method(
pid = pid,
... = ...
)
except ProjCntrException:
#handle error
#response generation
...
控制器(proj_cntr)负责确定给定的PID是否有效,给定的用户是否允许执行该操作以及其他业务逻辑验证。
我注意到我在不同的控制器中粘贴了很多像这样的代码:
if not project_object:
sys_logger.info('...')
raise ProjCntrException('PID %d does not exist' % pid)
把这些检查(验证)放在装饰器中似乎是最好的事情。 但是如果验证不通过,我不确定哪种错误处理模式是最佳实践。
1)我应该为每个装饰器创建特定的自定义异常(InvalidProjException,PermissionsException等)吗?
担心 :调用方法的catch块会显得臃肿。 另外,假设调用者知道被调用者的装饰器引发了什么异常,这是否很好?
2)装饰器将一个额外的错误参数传递给方法,并且方法决定引发什么异常。 这样调用方法就知道要预期和处理的异常类型。
担忧 :方法似乎有些过度设计和混乱。
对于详细的问题抱歉。 任何想法/想法都非常感激。
我最终使用装饰器并在其中抛出特定的异常。 例如:
@validate_pid
装饰器raises InvalidPidException()
,它被调用装饰方法的任何使用者的except块捕获。
目前的优势:
迄今为止的缺点:
选项1 :为您的装饰器创建特定的Exception
似乎是合乎逻辑的,因为这将有助于用户知道引发了哪个异常,以及为什么。 当然,异常的类型应该出现在装饰器文档字符串中,以便调用者能够知道期望的内容。 这样你就不会做出假设,用户知道发生了什么异常,但他已经阅读了文档 - 这更可能是假设。 但是,如果方法经常被调用,则调用者将不得不每次处理它。 这是使用库,API或其他人代码时的一部分。
选项2 :它不属于用户以确定将引发哪个异常。 例如,用户应该通过文档来了解它。 就API设计而言,这是凌乱和不直观的。
思考你的问题让我想到了Java的工作方式,特别是当你使用IDE时,当调用一个方法时,你将被IDE和通过打字机制警告 - 你应该try/catch
给定类型的异常。
但在你的情况下,将不可能用特定的消息提出正确的HTTPException
?
上一篇: Is it a good pattern to raise exceptions in a python decorator?