在python装饰器中引发异常是一种好模式吗?

在python装饰器中引发异常是一种好模式吗?,python,exception,error-handling,flask,Python,Exception,Error Handling,Flask,上下文:我为不同的API端点定义了Flask路由,每个端点使用特定参数(uid、项目id等)调用一个控制器类 控制器(proj_cntr)负责确定给定PID是否有效、是否允许给定用户执行操作以及其他业务逻辑验证 我注意到我在不同的控制器中粘贴了很多这样的代码: if not project_object: sys_logger.info('...') raise ProjCntrException('PID %d does not exist' % pid) 将这些检查(验证)

上下文:我为不同的API端点定义了Flask路由,每个端点使用特定参数(uid、项目id等)调用一个控制器类

控制器(proj_cntr)负责确定给定PID是否有效、是否允许给定用户执行操作以及其他业务逻辑验证

我注意到我在不同的控制器中粘贴了很多这样的代码:

if not project_object:
    sys_logger.info('...')
    raise ProjCntrException('PID %d does not exist' % pid)
将这些检查(验证)放在装饰器中似乎是最好的做法。但是如果验证没有通过,我不确定哪种错误处理模式是最佳实践

1)我是否应该为每个要引发的装饰者创建特定的自定义异常(InvalidProjeException、PermissionsException等)

关注点:调用方方法的catch块将看起来臃肿。另外,假设调用者知道被调用者的装饰器会引发哪些异常,这是否好呢

2)装饰程序向方法传递一个额外的错误参数,该方法决定引发什么异常。通过这种方式,调用方方法知道期望和处理的异常类型

关注点:方法似乎有点设计过度和混乱


对不起,我的问题太冗长了。非常感谢您的任何想法/想法。

选项1:为您的装饰师创建一个特定的
异常似乎是合乎逻辑的,因为这将帮助用户了解引发的异常(如果有)以及原因。当然,异常的类型应该出现在decorator docstring中,以便调用方能够知道将发生什么。这样,您就不会假设用户知道引发了什么异常,而是假设他已经阅读了文档,这更可能是一种假设。但是,如果经常调用该方法,则调用方每次都必须处理它。当使用库、API或其他人的代码时,这是交易的一部分

选项2:它不属于用户,用户无法确定将引发哪种异常。例如,用户应该通过文档了解这一点。就API设计而言,它既混乱又违反直觉

考虑到你的问题,它让我想到了Java的工作方式,特别是如果你使用IDE,当调用一个方法时,你会被IDE和键入机制警告你应该
try/catch
一个给定类型的异常


但是在您的情况下,不可能用特定的消息引发适当的
HTTPException

我最终使用了装饰器并在其中引发了特定的异常。例如:

@validate\u pid
decorator
引发invalidIDidexception()
,调用修饰方法的任何使用者的except块都会捕获到该异常

迄今为止的优势:

  • 控制器更干净,代码复制更少
  • 相当通用的解决方案,因为我在代码中使用这些“业务逻辑验证”装饰器
迄今为止的缺点:

  • decorator依赖于在调用修饰的方法时要传递的某些keyname参数,但其中一些参数没有在方法本身中使用。这可能导致方法签名中出现一些奇怪的“悬空”参数
  • 我有一些轻微的性能问题。例如:项目验证装饰器初始化一个会话并加载一个对象(项目),但该对象(项目)将在装饰方法本身中再次加载。只是看起来有点古怪
毫无疑问,我最终在decorator和decorred方法的docstring中尽可能多地输入了信息。
if not project_object:
    sys_logger.info('...')
    raise ProjCntrException('PID %d does not exist' % pid)