电子书 当前页面的脚本发生错误 异常处理的三个好习惯 | Python 工匠

11/28 05:09:02 来源网站:辅助卡盟平台

  1. raise error_codes.UNABLE_TO_UPVOTE

    raise error_codes.USER_HAS_BEEN_BANNED

    ... ...

    毫无意外,所有人都很喜欢用这种方式来返回错误码。因为它用起来非常方便辅助论坛,无论调用栈多深,只要你想给用户返回错误码,调用 raiseerror_codes.ANY_THING 就好。

    随着时间推移,项目也变得越来越庞大,抛出 APIErrorCode 的地方也越来越多。有一天,我正准备复用一个底层图片处理函数时,突然碰到了一个问题。

    我看到了一段让我非常纠结的代码:

    1. # 在某个处理图像的模块内部

      # /util/image/processor.py

      def process_image(...):

      try:

      image = Image.open(fp)

      except Exception:

      # 说明(非项目原注释):该异常将会被 Django 的中间件捕获,往前端返回

      # "上传的图片格式有误" 信息

      raise error_codes.INVALID_IMAGE_UPLOADED

      ... ...

      process_image 函数会尝试解析一个文件对象,如果该对象不能被作为图片正常打开,就抛出 error_codes.INVALID_IMAGE_UPLOADED(APIErrorCode子类) 异常,从而给调用方返回错误代码 JSON。

      让我给你从头理理这段代码。最初编写 process_image 时,我虽然把它放在了 util.image 模块里,但当时调这个函数的地方就只有 “处理用户上传图片的 POST 请求” 而已。为了偷懒,我让函数直接抛出 APIErrorCode 异常来完成了错误处理工作。

      再来说当时的问题。那时我需要写一个在后台运行的批处理图片脚本,而它刚好可以复用 process_image 函数所实现的功能。但这时不对劲的事情出现了,如果我想复用该函数,那么:

      我必须引入APIErrorCode异常类作为依赖来捕获异常

      这就是异常类抽象层级不一致导致的结果。APIErrorCode 异常类的意义,在于表达一种能够直接被终端用户(人)识别并消费的“错误代码”。它在整个项目里,属于最高层的抽象之一。但是出于方便,我们却在底层模块里引入并抛出了它。这打破了 image.processor 模块的抽象一致性,影响了它的可复用性和可维护性。

      这类情况属于“模块抛出了高于所属抽象层级的异常”。避免这类错误需要注意以下几点:

      在必要的地方进行异常包装与转换

      修改后的代码:

      1. # /util/image/processor.py

        class ImageOpenError(Exception):

        pass



        def process_image(...):

        try:

        image = Image.open(fp)

        except Exception as e:

        raise ImageOpenError(exc=e)

        ... ...


        # /app/views.py

        def foo_view_function(request):

        try:

        process_image(fp)

        except ImageOpenError:

        raise error_codes.INVALID_IMAGE_UPLOADED

        除了应该避免抛出高于当前抽象级别的异常外,我们同样应该避免泄露低于当前抽象级别的异常。

    暂无相关资讯
电子书 当前页面的脚本发生错误 异常处理的三个好习惯 | Python 工匠