python - 异常捕获 python 中的性能

标签 python performance exception-handling

我知道 python 中的异常在 try 方面很快,但在 catch 方面可能很昂贵。

这是否意味着:

try:
   some code
except MyException:
   pass

比这还快?

try:
   some code
except MyException as e:
   pass

最佳答案

除了 Francesco 的回答之外,捕获的(相对)昂贵的部分之一似乎是异常匹配:

>>> timeit.timeit('try:\n    raise KeyError\nexcept KeyError:\n    pass', number=1000000 )
1.1587663322268327
>>> timeit.timeit('try:\n    raise KeyError\nexcept:\n    pass', number=1000000 )
0.9180641582179874

查看 (CPython 2) 反汇编:

>>> def f():
...     try:
...         raise KeyError
...     except KeyError:
...         pass
... 
>>> def g():
...     try:
...         raise KeyError
...     except:
...         pass
... 
>>> dis.dis(f)
  2           0 SETUP_EXCEPT            10 (to 13)

  3           3 LOAD_GLOBAL              0 (KeyError)
              6 RAISE_VARARGS            1
              9 POP_BLOCK           
             10 JUMP_FORWARD            17 (to 30)

  4     >>   13 DUP_TOP             
             14 LOAD_GLOBAL              0 (KeyError)
             17 COMPARE_OP              10 (exception match)
             20 POP_JUMP_IF_FALSE       29
             23 POP_TOP             
             24 POP_TOP             
             25 POP_TOP             

  5          26 JUMP_FORWARD             1 (to 30)
        >>   29 END_FINALLY         
        >>   30 LOAD_CONST               0 (None)
             33 RETURN_VALUE        
>>> dis.dis(g)
  2           0 SETUP_EXCEPT            10 (to 13)

  3           3 LOAD_GLOBAL              0 (KeyError)
              6 RAISE_VARARGS            1
              9 POP_BLOCK           
             10 JUMP_FORWARD             7 (to 20)

  4     >>   13 POP_TOP             
             14 POP_TOP             
             15 POP_TOP             

  5          16 JUMP_FORWARD             1 (to 20)
             19 END_FINALLY         
        >>   20 LOAD_CONST               0 (None)
             23 RETURN_VALUE        

请注意,catch block 无论如何都会加载异常并将其与 KeyError 进行匹配。事实上,将 except KeyError 看成 ke 情况:

>>> def f2():
...     try:
...         raise KeyError
...     except KeyError as ke:
...         pass
... 
>>> dis.dis(f2)
  2           0 SETUP_EXCEPT            10 (to 13)

  3           3 LOAD_GLOBAL              0 (KeyError)
              6 RAISE_VARARGS            1
              9 POP_BLOCK           
             10 JUMP_FORWARD            19 (to 32)

  4     >>   13 DUP_TOP             
             14 LOAD_GLOBAL              0 (KeyError)
             17 COMPARE_OP              10 (exception match)
             20 POP_JUMP_IF_FALSE       31
             23 POP_TOP             
             24 STORE_FAST               0 (ke)
             27 POP_TOP             

  5          28 JUMP_FORWARD             1 (to 32)
        >>   31 END_FINALLY         
        >>   32 LOAD_CONST               0 (None)
             35 RETURN_VALUE    

唯一的区别是单个 STORE_FAST 用于存储异常值(在匹配的情况下)。同样,有几个异常匹配:

>>> def f():
...     try:
...         raise ValueError
...     except KeyError:
...         pass
...     except IOError:
...         pass
...     except SomeOtherError:
...         pass
...     except:
...         pass
... 
>>> dis.dis(f)
  2           0 SETUP_EXCEPT            10 (to 13)

  3           3 LOAD_GLOBAL              0 (ValueError)
              6 RAISE_VARARGS            1
              9 POP_BLOCK           
             10 JUMP_FORWARD            55 (to 68)

  4     >>   13 DUP_TOP             
             14 LOAD_GLOBAL              1 (KeyError)
             17 COMPARE_OP              10 (exception match)
             20 POP_JUMP_IF_FALSE       29
             23 POP_TOP             
             24 POP_TOP             
             25 POP_TOP             

  5          26 JUMP_FORWARD            39 (to 68)

  6     >>   29 DUP_TOP             
             30 LOAD_GLOBAL              2 (IOError)
             33 COMPARE_OP              10 (exception match)
             36 POP_JUMP_IF_FALSE       45
             39 POP_TOP             
             40 POP_TOP             
             41 POP_TOP             

  7          42 JUMP_FORWARD            23 (to 68)

  8     >>   45 DUP_TOP             
             46 LOAD_GLOBAL              3 (SomeOtherError)
             49 COMPARE_OP              10 (exception match)
             52 POP_JUMP_IF_FALSE       61
             55 POP_TOP             
             56 POP_TOP             
             57 POP_TOP             

  9          58 JUMP_FORWARD             7 (to 68)

 10     >>   61 POP_TOP             
             62 POP_TOP             
             63 POP_TOP             

 11          64 JUMP_FORWARD             1 (to 68)
             67 END_FINALLY         
        >>   68 LOAD_CONST               0 (None)
             71 RETURN_VALUE      

将复制异常并尝试将其与列出的每个异常进行匹配,一个接一个地匹配,直到找到匹配项,这(可能)被暗示为“捕获性能不佳”。

关于python - 异常捕获 python 中的性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36642633/

相关文章:

python - 使用多个 Gunicorn 工作线程时仅启动 Django 配置应用程序一次

python - 如何从树状文件目录文本文件创建嵌套字典对象?

performance - 人眼能否感知图像加载时间的 10 毫秒延迟

java - Java异常层次结构背后的基本原理

python - 以 append 模式写入python中的新行

performance - 如何降低 O(N^2) C-index 函数的时间复杂度?

c++ - 为什么 move 构造函数不更快?

c++ - 异常处理,无法理解 :(

java - 什么时候可以捕获 RuntimeException

python - 循环使用两个计数器