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

2024-05-29 03:09:21 发布

您现在位置: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-u-cntr)负责确定,比如,给定的PID是否有效,是否允许给定的用户执行操作,以及其他业务逻辑验证。在

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

^{pr2}$

将这些检查(验证)放在decorator中似乎是最好的做法。但我不确定如果验证不通过,哪种错误处理模式是最佳实践。在

1)我是否应该为每个decorator创建特定的自定义异常(InvalidProjException、PermissionsException等)?在

关注点:调用方方法的catch块看起来会膨胀。另外,假设调用者知道被调用者的装饰者引发了什么异常,这样做是否好?在

2)decorator向方法传递一个额外的错误参数,该方法决定引发哪个异常。通过这种方式,调用方方法可以知道要期望和处理的异常类型。在

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

很抱歉这个冗长的问题。任何想法/想法都非常感谢。在


Tags: sample方法api参数定义decoratorrequire控制器
2条回答

最后我使用了decorator并在其中抛出了特定的异常。例如:

@validate_pid装饰器raises InvalidPidException(),它在调用装饰方法的任何使用者的except块中捕获。在

目前的优势:

  • 控制器更干净,代码复制更少。在
  • 相当通用的解决方案,因为我在代码中使用了这些“业务逻辑验证”修饰符。在

目前的缺点:

  • decorator依赖于在调用decorated方法时要传递的某些keyname参数,但是其中一些参数并没有在方法本身中使用。这会导致方法签名中出现一些奇怪的“悬空”参数。在
  • 我有一些小的性能问题。例如:projectvalidationdecorator初始化一个会话并加载一个对象(项目),而这个对象(项目)只会在装饰方法本身中再次加载。只是看起来有点紧张。在

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

选项2:它不属于用户来确定将引发哪个异常。例如,用户应该通过文档了解它。从API设计的角度来看,这是一个混乱和反直觉的问题。在

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

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

相关问题 更多 >

    热门问题