在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块捕获。

目前的优势:

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

  • 该装饰依赖于特定的键名参数时,装饰方法被调用传递,但一些这些参数都没有方法本身内使用。 这可能会导致方法签名中出现一些奇怪的“悬挂”参数。
  • 我有一些小的性能问题。 例如:项目审定装饰初始化会话并加载一个对象(项目)仅是在装饰方法本身再次加载。 只是似乎有点janky。

  • 选项1 :为您的装饰器创建特定的Exception似乎是合乎逻辑的,因为这将有助于用户知道引发了哪个异常,以及为什么。 当然,异常的类型应该出现在装饰器文档字符串中,以便调用者能够知道期望的内容。 这样你就不会做出假设,用户知道发生了什么异常,但他已经阅读了文档 - 这更可能是假设。 但是,如果方法经常被调用,则调用者将不得不每次处理它。 这是使用库,API或其他人代码时的一部分。

    选项2 :它不属于用户以确定将引发哪个异常。 例如,用户应该通过文档来了解它。 就API设计而言,这是凌乱和不直观的。

    思考你的问题让我想到了Java的工作方式,特别是当你使用IDE时,当调用一个方法时,你将被IDE和通过打字机制警告 - 你应该try/catch给定类型的异常。

    但在你的情况下,将不可能用特定的消息提出正确的HTTPException

    链接地址: http://www.djcxy.com/p/24477.html

    上一篇: Is it a good pattern to raise exceptions in a python decorator?

    下一篇: How to check if a svn command needs authentication