Python 3.11 你应该试试的超酷特性:七、Zero-Cost Exceptions零开销异常

384 阅读2分钟

Python 3.11 你应该试试的超酷特性

Python 3.11在10月24日发布。它是Python最新版本,运行速度更快且更佳友好。在经过17个月的研发,终于到了可以使用的黄金时期。

和每个发布版本一样,Python 3.11做了大量的变更及提高。你可以通过查看文档来了解大部分内容。这里,我们会阐述最酷且最有影响力的新特性。

教程里将涵盖如下内容:

  • 更好的错误信息来帮助代码追踪
  • Faster CPython项目加速代码执行
  • 在异步代码中使用Task和exception groups
  • Python静态类型新增的几个类型特性
  • 原生支持TOML格式配置文件

如果你想运行本教程所提供的示例文件,你需要先安装Python 3.11.

零开销异常

Python 3.11内部异常机制有一些不同。异常对象更加轻量,异常处理在except子句不触发时,对try...except语句块优化减少开销,

zero-cost exceptions灵感来自C++和Java语言。旨在在快乐路径时(即无异常发生)几乎没有任何其它多余的开销,发生异常的情况仍需要开销处理。

zero-cost exception通过编译器构建字节码时创建一个jump table。这些表在异常发生时使用。如果没发生异常的话,try语句没有任何运行时开销。

我们再来看看早期的倒数例子。我们添加了一些异常处理:

>>> def inverse(number):
...     try:
...             return 1 / number
...     except ZeroDivisionError:
...             print("0 has no inverse")

如果我们计算0的倒数时,ZeroDivisionError会抛出。这里我们使用异常补货然后打印了描述信息。我们可以使用dis来看看底层的字节码:

>>> import dis
>>> dis.dis(inverse)
  1           0 RESUME                   0

  2           2 NOP

  3           4 LOAD_CONST               1 (1)
              6 LOAD_FAST                0 (number)
              8 BINARY_OP               11 (/)
             12 RETURN_VALUE
        >>   14 PUSH_EXC_INFO

  4          16 LOAD_GLOBAL              0 (ZeroDivisionError)
             28 CHECK_EXC_MATCH
             30 POP_JUMP_FORWARD_IF_FALSE    19 (to 70)
             32 POP_TOP

  5          34 LOAD_GLOBAL              3 (NULL + print)
             46 LOAD_CONST               2 ('0 has no inverse')
             48 PRECALL                  1
             52 CALL                     1
             62 POP_TOP
             64 POP_EXCEPT
             66 LOAD_CONST               0 (None)
             68 RETURN_VALUE

  4     >>   70 RERAISE                  0
        >>   72 COPY                     3
             74 POP_EXCEPT
             76 RERAISE                  1
ExceptionTable:
  4 to 10 -> 14 [0]
  14 to 62 -> 72 [1] lasti
  70 to 70 -> 72 [1] lasti

咱也不需要去过多关心字节码意义。但是我们可以简单观察出最左边其实就会对应代码行。行2就是try,转换为了NOP指令,该指令啥也不干。底部那东西就是我们提到的exception table。该jump table就是用来专门处理异常的。

Python 3.10及早期,云行时异常处理有一些开销。例如,try语句编译成SETUP_FINALLY指令,它包含了一个指向第一个exception块的指针。通过引入jump table无异常发生时得到速度提升。

Zero-cost exceptions非常适合Easier to ask forgiveness than permission编码风格代码,它风格会大量使用try...except语句。